#include "PCIe_Root_Complex.h"

PCIe_Root_Complex::PCIe_Root_Complex(sc_module_name		name_,
									 PCIe_id_t			id_,
									 PCIe_id_t			North_DMA_id_,
									 unsigned			North_Main_DMA_PRD_start_addr_,
									 unsigned			North_DMA_cmd_reg_start_addr_,
									 unsigned			North_Main_DMA_check_reg_start_addr_,
									 PCIe_address_space	addr_DRAM_mem_1_,
									 PCIe_address_space	addr_DRAM_io_,
									 PCIe_address_space	addr_DRAM_conf_,
									 PCIe_address_space	addr_DMI_mem_1_,
									 PCIe_address_space	addr_DMI_io_,
									 PCIe_address_space	addr_DMI_conf_,
									 PCIe_address_space	addr_DRAM_mem_2_,
									 PCIe_address_space	addr_DMI_mem_2_,
									 unsigned			System_type_,
									 unsigned			DRAM_rank_index_,
									 unsigned			DRAM_bank_index_,
									 unsigned			DRAM_row_index_,
									 unsigned			DRAM_col_index_)
	: sc_module								(name_)
	, North_Main_DMA_PRD_start_addr			(0x0, North_Main_DMA_PRD_start_addr_)
	, North_Main_DMA_PRD_start_addr_init	(0x0, North_Main_DMA_PRD_start_addr_)
	, North_DMA_cmd_reg_start_addr			(0x0, North_DMA_cmd_reg_start_addr_)
	, North_Main_DMA_check_reg_start_addr	(0x0, North_Main_DMA_check_reg_start_addr_)
	, System_type							(System_type_)
	, CPU_active							(false)
	, CPU_active_time						(0, SC_NS)
	, id									(id_)
	, North_DMA_id							(North_DMA_id_)
	//, graphic_port							(name_, EXTERNAL_GRAPHIC_ID, x16)
	, DMI_port								(name_, SWITCH_ID, x4)
	, DMI_current_state						(PL_IDLE)
	, DMI_sequence_number					(0)
	, DMI_NAK_sequence_number				(0)
	, DMI_NAK_free_sequence_number			(0)
	, DMI_stop								(false)
	, CPU_buffer_TLP_down_in				(0)
	, CPU_buffer_TLP_down_out				(0)
	, CPU_buffer_TLP_down_time				(0, SC_NS)
	, CPU_buffer_TLP_up_in					(0)
	, CPU_buffer_TLP_up_out					(0)
	, CPU_buffer_TLP_up_time				(0, SC_NS)
	, DMI_buffer_DLL_TLP_down_in			(0)
	, DMI_buffer_DLL_TLP_down_out			(0)
	, DMI_buffer_DLL_TLP_down_ack_nak		(0)
	, DMI_buffer_DLL_TLP_down_time			(0, SC_NS)
	, DMI_buffer_DLL_TLP_up_in				(0)
	, DMI_buffer_DLL_TLP_up_out				(0)
	, DMI_buffer_DLL_TLP_up_time			(0, SC_NS)
	, DRAM_buffer_TLP_down_in				(0)
	, DRAM_buffer_TLP_down_out				(0)
	, DRAM_buffer_TLP_down_time				(0, SC_NS)
	, DRAM_buffer_TLP_up_in					(0)
	, DRAM_buffer_TLP_up_out				(0)
	, DRAM_buffer_TLP_up_time				(0, SC_NS)
	, DMI_buffer_TLP_down_in				(0)
	, DMI_buffer_TLP_down_out				(0)
	, DMI_buffer_TLP_down_time				(0, SC_NS)
	, DMI_buffer_TLP_up_in					(0)
	, DMI_buffer_TLP_up_out					(0)
	, DMI_buffer_TLP_up_time				(0, SC_NS)
	, DMI_buffer_DLLP_down_in				(0)
	, DMI_buffer_DLLP_down_out				(0)
	, DMI_buffer_DLLP_down_time				(0, SC_NS)
	, DMI_buffer_DLLP_up_in					(0)
	, DMI_buffer_DLLP_up_out				(0)
	, DMI_buffer_DLLP_up_time				(0, SC_NS)
	, DMI_DLL_TLP_seq_num_cnt				(1)
	, DMI_TLP_header_cnt					(0)
	, DMI_TLP_data_cnt						(0)
	, DMI_TLP_ECRC_cnt						(3)
	, DMI_DLL_TLP_LCRC_cnt					(3)
	, DMI_DLLP_data_cnt						(0)
	, DMI_DLLP_CRC_cnt						(1)
	, DMI_granted_packet_type				(0)
	, DRAM_rank_index						(DRAM_rank_index_)
	, DRAM_bank_index						(DRAM_bank_index_)
	, DRAM_row_index						(DRAM_row_index_)
	, DRAM_col_index						(DRAM_col_index_)
	, DRAM_refresh_cnt						(DDR_DEFAULT_tRFCI-(DDR_DEFAULT_tRCD+DDR_DEFAULT_CL+DDR_DEFAULT_BURST_LENGTH+DDR_DEFAULT_tRP))
	, DRAM_refresh_enable					(false)
	, DRAM_refresh_enable_time				(0,SC_NS)
	, North_Main_DMA_end					(0x0)
	, North_SSD_DMA_end						(0x0)
	, South_Main_DMA_end					(0x0)
	, South_SSD_DMA_end						(0x0)
	, North_Main_DMA_enable					(false)
	, North_Main_DMA_burst_change			(false)
	, North_Main_DMA_PRD_fetch_commanded	(false)
	, North_Main_DMA_PRD_fetched			(false)
	, North_Main_DMA_requested_1st			(false)
	, North_Main_DMA_requested_2nd			(false)
	, North_Main_DMA_buffered				(false)
	, North_Main_DMA_write_check			(false)
	, North_SSD_DMA_end_check				(false)
	, North_SSD_DMA_stop					(false)
{
	system_address_map.push_back(addr_DRAM_mem_1_);
	system_address_map.push_back(addr_DRAM_io_);
	system_address_map.push_back(addr_DRAM_conf_);
	system_address_map.push_back(addr_DMI_mem_1_);
	system_address_map.push_back(addr_DMI_io_);
	system_address_map.push_back(addr_DMI_conf_);
	system_address_map.push_back(addr_DRAM_mem_2_);
	system_address_map.push_back(addr_DMI_mem_2_);

	SC_THREAD(CPU_make_action);
	dont_initialize();
	sensitive << CPU_CLK;

	SC_THREAD(CPU_switch_action);
	dont_initialize();
	sensitive << CPU_CLK.pos();

	SC_THREAD(DRAM_switch_action);
	dont_initialize();
	sensitive << CPU_CLK.pos();

	SC_THREAD(DMI_make_action);
	dont_initialize();
	sensitive << CPU_CLK.pos();

	SC_THREAD(DMI_switch_action);
	dont_initialize();
	sensitive << CPU_CLK.pos();

	SC_THREAD(DMI_TLP_send_action);
	dont_initialize();
	sensitive << DMI_CLK.pos();

	SC_THREAD(DMI_ack_nak_action);
	dont_initialize();
	sensitive << DMI_CLK.pos();

	SC_THREAD(DMI_DLLP_send_action);
	dont_initialize();
	sensitive << DMI_CLK.pos();

	SC_THREAD(DRAM_refresh_count_action);
	dont_initialize();
	sensitive << DRAM_CLK;

	SC_THREAD(DRAM_timing_control_action);
	dont_initialize();
	sensitive << DRAM_CLK;

	SC_THREAD(SSD_timing_control_action);
	dont_initialize();
	sensitive << DRAM_CLK;

	SC_THREAD(North_Main_DMA_action);
	dont_initialize();
	sensitive << DRAM_CLK.pos();
}

PCIe_Root_Complex::~PCIe_Root_Complex()
{
	for (int i=0; i<MAX_BUFFER_RC; i++)
	{
		delete[] CPU_buffer_TLP_down[i].header;
		if (CPU_buffer_TLP_down[i].with_data)
			delete[] CPU_buffer_TLP_down[i].data;

		delete[] CPU_buffer_TLP_up[i].header;
		if (CPU_buffer_TLP_up[i].with_data)
			delete[] CPU_buffer_TLP_up[i].data;

		delete[] DMI_buffer_DLL_TLP_down[i].TLP.header;
		if (DMI_buffer_DLL_TLP_down[i].TLP.with_data)
			delete[] DMI_buffer_DLL_TLP_down[i].TLP.data;

		delete[] DMI_buffer_DLL_TLP_up[i].TLP.header;
		if (DMI_buffer_DLL_TLP_up[i].TLP.with_data)
			delete[] DMI_buffer_DLL_TLP_up[i].TLP.data;

		delete[] DRAM_buffer_TLP_down[i].header;
		if (DRAM_buffer_TLP_down[i].with_data)
			delete[] DRAM_buffer_TLP_down[i].data;

		delete[] DRAM_buffer_TLP_up[i].header;
		if (DRAM_buffer_TLP_up[i].with_data)
			delete[] DRAM_buffer_TLP_up[i].data;

		delete[] DMI_buffer_TLP_down[i].header;
		if (DMI_buffer_TLP_down[i].with_data)
			delete[] DMI_buffer_TLP_down[i].data;

		delete[] DMI_buffer_TLP_up[i].header;
		if (DMI_buffer_TLP_up[i].with_data)
			delete[] DMI_buffer_TLP_up[i].data;
	}
}

const bool
PCIe_Root_Complex::CPU_init_transaction(bool is_write_,
										CPU_addr_t addr_,
										unsigned data_length_)
{
	CPU_is_write = is_write_;
	CPU_address = addr_;
	CPU_data_length = data_length_;
	CPU_data_buffer = new CPU_data_t[data_length_];
	CPU_data_cnt = 0;
	CPU_data_ready = false;
	CPU_write_done = false;
	CPU_active = true;
	CPU_active_time = sc_time_stamp();
	CPU_write_reguest_completed = false;

	return true;
}

const bool
PCIe_Root_Complex::CPU_end_transaction()
{
	CPU_active = false;
	CPU_active_time = sc_time_stamp();
	if (CPU_is_write)
	{
		CPU_write_reguest_completed = true;
		CPU_write_reguest_completed_time = sc_time_stamp();
	}
	else
	{
		delete[] CPU_data_buffer;
	}

	return true;
}

const bool
PCIe_Root_Complex::CPU_is_ready() const
{
	return CPU_data_ready;
}

const bool
PCIe_Root_Complex::CPU_is_done() const
{
	return CPU_write_done;
}

const CPU_data_t
PCIe_Root_Complex::CPU_read_data()
{
	CPU_data_t return_data;
	
	return_data = CPU_data_buffer[CPU_data_cnt++];
	return return_data;
}

const bool
PCIe_Root_Complex::CPU_write_data(CPU_data_t data_)
{
	CPU_data_buffer[CPU_data_cnt++] = data_;

	return true;
}

const bool
PCIe_Root_Complex::CPU_check_interrupt(unsigned interrupt_type_)
{
	bool return_val = false;
	switch (interrupt_type_)
	{
	case 1:
		if (South_Main_DMA_end)
		{
			South_Main_DMA_end = 0x0;
			return_val = true;
		}
		break;
	case 2:
		if (North_Main_DMA_end)
		{
			North_Main_DMA_end = 0x0;
			return_val = true;
		}
		break;
	case 3:
		if ((North_Main_DMA_end & North_SSD_DMA_end))
		{
			North_Main_DMA_end = 0x0;
			North_SSD_DMA_end = 0x0;
			return_val = true;
		}
		break;
	case 4:
		if ((South_Main_DMA_end & South_SSD_DMA_end))
		{
			South_Main_DMA_end = 0x0;
			South_SSD_DMA_end = 0x0;
			return_val = true;
		}
		break;
	default:
		cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> Unknown interrupt!" << endl;
		sc_stop();
	}

	return return_val;
}

void
PCIe_Root_Complex::PL_send_symbol(PCIe_id_t		id_,
								  PCIe_symbol_t	symbol_)
{
	switch (symbol_)
	{
	case STP:
		if (id_ == DMI_port.get_id())
		{
			DMI_DLL_TLP_seq_num_cnt = 1;
			DMI_TLP_header_cnt = 0;
			DMI_TLP_data_cnt =	0;
			DMI_TLP_ECRC_cnt = 3;
			DMI_DLL_TLP_LCRC_cnt = 3;
			DMI_is_STP = true;
			DMI_current_state = TLP_SEQ_NUM;
		}
		break;
	case SDP:
		if (id_ == DMI_port.get_id())
		{
			DMI_DLLP_data_cnt = 0;
			DMI_DLLP_CRC_cnt = 1;
			DMI_is_STP = false;
			DMI_current_state = DLLP_TYPE;
		}
		break;
	case END:
		if (id_ == DMI_port.get_id())
		{
			if (DMI_is_STP)
			{
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Sequence Number : " << hex << DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].sequence_number << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
				int limit;
				if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.DW4_header)
					limit = 16;
				else
					limit = 12;
				for (int i=0; i<limit ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.header[i] << dec << " ";
				}
				cout << endl;
				if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.with_data)
				{
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
					if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length == 0)
					{
						for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					else
					{
						for (int i=0; i<DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length*PCIe_DOUBLE_WORD; i++)
						{
							cout.width(2);
							cout.fill('0');
							switch (i%4)
							{
							case 0:
								cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4]>>24) & 0xFF) << dec << " ";
								break;
							case 1:
								cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4]>>16) & 0xFF) << dec << " ";
								break;
							case 2:
								cout << hex << ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4]>>8) & 0xFF) << dec << " ";
								break;
							case 3:
								cout << hex << (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[i/4] & 0xFF) << dec << " | ";
								break;
							}
						}
					}
					cout << endl;
				}
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.ECRC << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "LCRC : " << hex << DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].LCRC << dec << endl;
#endif
				unsigned short received_seq_num;
				received_seq_num = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].sequence_number;
				if (((DMI_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DMI_buffer_TLP_up_out) && (DMI_NAK_free_sequence_number == received_seq_num))
				{
					DMI_is_NAK = false;
					DMI_NAK_free_sequence_number = (received_seq_num+1)%4096;
				}
				else
				{
					DMI_is_NAK = true;
				}
				DMI_buffer_DLL_TLP_up_in = (DMI_buffer_DLL_TLP_up_in+1)%MAX_BUFFER_RC;
				DMI_buffer_DLL_TLP_up_time = sc_time_stamp();
			}
			else
			{
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP Type : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].type << dec << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP Data : ";
				for (int i=0; i<3 ; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].data[i] << dec << " ";
				}
				cout << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DLLP CRC : " << hex << DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].CRC << dec << endl;
#endif
				if (DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].type == NAK)
				{
					unsigned short received_seq_num;
					received_seq_num = ((unsigned short)DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].data[1])<<8 | (unsigned short)DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].data[2];
					if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_ack_nak].sequence_number == received_seq_num)
					{
						DMI_buffer_DLL_TLP_down_out = DMI_buffer_DLL_TLP_down_ack_nak;
						DMI_NAK_sequence_number = received_seq_num;
						DMI_stop = true;
					}
				}
				else
				{
					delete[] DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_ack_nak].TLP.header;
					if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_ack_nak].TLP.with_data)
						delete[] DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_ack_nak].TLP.data;
					DMI_buffer_DLL_TLP_down_ack_nak = (DMI_buffer_DLL_TLP_down_ack_nak+1)%MAX_BUFFER_RC;
				}
				DMI_buffer_DLLP_up_in = (DMI_buffer_DLLP_up_in+1)%MAX_BUFFER_RC;
				DMI_buffer_DLLP_up_out = (DMI_buffer_DLLP_up_out+1)%MAX_BUFFER_RC;
				DMI_buffer_DLLP_up_time = sc_time_stamp();
			}
			DMI_current_state = PL_IDLE;
		}
		break;
	default :
		cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unknown Symbol!" << endl << flush;
		sc_stop();
	}
}

const bool
PCIe_Root_Complex::DLL_send_sequence_number_byte(PCIe_id_t	id_,
												 byte		seq_num_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_DLL_TLP_seq_num_cnt != 0)
		{
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].sequence_number = 0x0;
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].sequence_number = seq_num_<<8;
			DMI_DLL_TLP_seq_num_cnt--;
		}
		else
		{
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].sequence_number |= seq_num_;
			DMI_DLL_TLP_seq_num_cnt = 1;
			DMI_current_state = TLP_HEADER;
		}
	}

	return true;
}

const bool
PCIe_Root_Complex::DLL_send_type_byte(PCIe_id_t	id_,
									  byte		type_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].type = (PCIe_DLLP_type_t)type_byte_;
		DMI_current_state = DLLP_DATA;
	}

	return true;
}

const bool
PCIe_Root_Complex::DLL_send_data_byte(PCIe_id_t	id_,
									  byte		data_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].data[DMI_DLLP_data_cnt] = data_byte_;
		if (DMI_DLLP_data_cnt != 2)
		{
			DMI_DLLP_data_cnt++;
		}
		else
		{
			DMI_DLLP_data_cnt = 0;
			DMI_current_state = DLLP_CRC;
		}
	}

	return true;
}

const bool
PCIe_Root_Complex::DLL_send_CRC_byte(PCIe_id_t	id_,
									 byte		CRC_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_DLLP_CRC_cnt == 1)
			DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].CRC = 0x0;
		DMI_buffer_DLLP_up[DMI_buffer_DLLP_up_in].CRC |= (((unsigned short)CRC_byte_)<<8*DMI_DLLP_CRC_cnt);
		if (DMI_DLLP_CRC_cnt != 0)
		{
			DMI_DLLP_CRC_cnt--;
		}
		else
		{
			DMI_DLLP_CRC_cnt = 1;
			DMI_current_state = PL_IDLE;
		}
	}

	return true;
}

const bool
PCIe_Root_Complex::DLL_send_LCRC_byte(PCIe_id_t	id_,
									  byte		LCRC_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_DLL_TLP_LCRC_cnt == 3)
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].LCRC = 0x0;
		DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].LCRC |= (((unsigned)LCRC_byte_)<<8*DMI_DLL_TLP_LCRC_cnt);
		if (DMI_DLL_TLP_LCRC_cnt != 0)
		{
			DMI_DLL_TLP_LCRC_cnt--;
		}
		else
		{
			DMI_DLL_TLP_LCRC_cnt = 3;
			DMI_current_state = PL_IDLE;
		}
	}

	return true;
}

void
PCIe_Root_Complex::TL_send_header_byte(PCIe_id_t	id_,
									   byte			header_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_TLP_header_cnt == 0)
		{
			if (0x1 & (header_byte_>>5))
			{
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.DW4_header = true;
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.header = new byte[PCIe_DOUBLE_WORD*4];
			}
			else
			{
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.DW4_header = false;
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.header = new byte[PCIe_DOUBLE_WORD*3];
			}
			if (0x1 & (header_byte_>>6))
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.with_data = true;
			else
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.with_data = false;
		}
		DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.header[DMI_TLP_header_cnt] = header_byte_;
		if (DMI_TLP_header_cnt == 2)
		{
			if (header_byte_>>7)
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.TLP_digest = true;
			else
				DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.TLP_digest = false;
		}
		else if (DMI_TLP_header_cnt == 3)
		{
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length = (((unsigned short)(0x3 & DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.header[2]))<<8) | ((unsigned short)DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.header[3]);
			if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.with_data)
			{
				if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length == 0)
				{
					DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data = new unsigned[1024];
				}
				else
				{
					DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data = new unsigned[DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length];
				}
			}
		}
		DMI_TLP_header_cnt++;
		if (DMI_TLP_header_cnt == 12 && !DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.DW4_header)
		{
			DMI_TLP_header_cnt = 0;
			if ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length == 0) && (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.with_data))
				DMI_current_state = TLP_ECRC;
			else
				DMI_current_state = TLP_DATA;
		}
		if (DMI_TLP_header_cnt == 16 && DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.DW4_header)
		{
			DMI_TLP_header_cnt = 0;
			if ((DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length == 0) && (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.with_data))
				DMI_current_state = TLP_ECRC;
			else
				DMI_current_state = TLP_DATA;
		}
	}
}

void
PCIe_Root_Complex::TL_send_data_byte(PCIe_id_t	id_,
									 byte		data_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		switch(DMI_TLP_data_cnt%4)
		{
		case 0:
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[DMI_TLP_data_cnt/4] = 0;
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<24;
			break;
		case 1:
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<16;
			break;
		case 2:
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_)<<8;
			break;
		case 3:
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.data[DMI_TLP_data_cnt/4] |= ((unsigned)data_byte_);
			break;
		}
		DMI_TLP_data_cnt++;
		if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length == 0)
		{
			if (DMI_TLP_data_cnt == 1024*PCIe_DOUBLE_WORD)
			{
				DMI_TLP_data_cnt = 0;
				DMI_current_state = TLP_ECRC;
			}
		}
		else
		{
			if (DMI_TLP_data_cnt == DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.length*PCIe_DOUBLE_WORD)
			{
				DMI_TLP_data_cnt = 0;
				DMI_current_state = TLP_ECRC;
			}
		}
	}
}

void
PCIe_Root_Complex::TL_send_ECRC_byte(PCIe_id_t	id_,
									 byte		ECRC_byte_)
{
	if (id_ == DMI_port.get_id())
	{
		if (DMI_TLP_ECRC_cnt == 3)
			DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.ECRC = 0x0;
		DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_in].TLP.ECRC |= (((unsigned)ECRC_byte_)<<8*DMI_TLP_ECRC_cnt);
		if (DMI_TLP_ECRC_cnt != 0)
		{
			DMI_TLP_ECRC_cnt--;
		}
		else
		{
			DMI_TLP_ECRC_cnt = 3;
			DMI_current_state = TLP_LCRC;
		}
	}
}

const bool
PCIe_Root_Complex::arbitrate_port(PCIe_id_t	id_,
								  unsigned	packet_type_)
{
	bool return_val = true;

	if (id_ == DMI_port.get_id())
	{
		if ((DMI_buffer_DLL_TLP_down_in != DMI_buffer_DLL_TLP_down_out) && (DMI_buffer_DLLP_down_in != DMI_buffer_DLLP_down_out))
		{
			if (packet_type_ == DMI_granted_packet_type)
				DMI_granted_packet_type = (DMI_granted_packet_type+1)%(DMI_NUM_OF_VIRTUAL_CHANNEL_RC+1);
			else
				return_val = false;
		}
		else
		{
			DMI_granted_packet_type = (packet_type_+1)%(DMI_NUM_OF_VIRTUAL_CHANNEL_RC+1);
		}
	}

	return return_val;
}

const unsigned
PCIe_Root_Complex::decode_address(PCIe_address	addr_) const
{
	unsigned return_code;

	for (int i=0;i<system_address_map.size();i++)
	{
		if ((addr_.high_address >= system_address_map[i].start_addr.high_address) && (addr_.high_address <= system_address_map[i].end_addr.high_address))
		{
			if (system_address_map[i].start_addr.high_address == system_address_map[i].end_addr.high_address)
			{
				if ((addr_.low_address >= system_address_map[i].start_addr.low_address) && (addr_.low_address <= system_address_map[i].end_addr.low_address))
				{
					return_code = i;
					break;
				}
			}
			else
			{
				if (addr_.high_address == system_address_map[i].start_addr.high_address)
				{
					if (addr_.low_address >= system_address_map[i].start_addr.low_address)
					{
						return_code = i;
						break;
					}
				}
				else if (addr_.high_address <= system_address_map[i].end_addr.high_address)
				{
					if (addr_.low_address <= system_address_map[i].end_addr.low_address)
					{
						return_code = i;
						break;
					}
				}
				else
				{
					return_code = i;
					break;
				}
			}
		}
	}

	sc_assert((return_code>=0) && (return_code<system_address_map.size()));
	return return_code;
}

const char*
PCIe_Root_Complex::SDRAM_get_state_name(SDRAM_state_t	state_) const
{
	char* state_name = new char[20];

	switch(state_) {
	case 0:
		state_name = "POWER_ON";
		break;
	case 1:
		state_name = "SDRAM_IDLE";
		break;
	case 2:
		state_name = "ROW_ACT";
		break;
	case 3:
		state_name = "READ_AP";
		break;
	case 4:
		state_name = "READ";
		break;
	case 5:
		state_name = "WRITE_AP";
		break;
	case 6:
		state_name = "WRITE";
		break;
	case 7:
		state_name = "PRECHARGE";
		break;
	case 8:
		state_name = "MRS";
		break;
	case 9:
		state_name = "AUTO_REF";
		break;
	case 10:
		state_name = "SELF_REF";
		break;
	default:
		state_name = "NULL";
	}

	return state_name;
}

void
PCIe_Root_Complex::CPU_make_action()
{
	PCIe_TLP tlp;
	byte CPU_tag = 0;
	unsigned* data;

	while (true)
	{
		if((CPU_active) && (CPU_active_time != sc_time_stamp()))
		{
			if (!CPU_is_write)
			{
				if (CPU_address.high_address == 0x0)
					if (CPU_data_length == 512)
						tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.low_address, NULL, 0);
					else
						tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 2*CPU_data_length, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.low_address, NULL, 0);
				else
					if (CPU_data_length == 512)
						tlp = construct_TLP_Request_Memory_64(false, MEMORY, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.high_address, CPU_address.low_address, NULL, 0);
					else
						tlp = construct_TLP_Request_Memory_64(false, MEMORY, 0, true, false, false, false, 2*CPU_data_length, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.high_address, CPU_address.low_address, NULL, 0);
				while ((CPU_buffer_TLP_down_in+1)%MAX_BUFFER_RC == CPU_buffer_TLP_down_out)
					wait();
				CPU_buffer_TLP_down[CPU_buffer_TLP_down_in] = tlp;
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Target Buffer : CPU" << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
				if (CPU_address.high_address == 0x0)
				{
					for (int i=0; i<3*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						cout << hex << (unsigned)tlp.header[i] << dec << " ";
					}
				}
				else
				{
					for (int i=0; i<4*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						cout << hex << (unsigned)tlp.header[i] << dec << " ";
					}
				}
				cout << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << tlp.ECRC << dec << endl;
#endif
				CPU_buffer_TLP_down_in = (CPU_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
				CPU_buffer_TLP_down_time = sc_time_stamp();
				wait();
				while((CPU_buffer_TLP_up_in == CPU_buffer_TLP_up_out) || (CPU_buffer_TLP_up_time == sc_time_stamp()) || ((PCIe_TLP_type_t)(CPU_buffer_TLP_up[CPU_buffer_TLP_up_out].header[0] & 0x1F) != COMPLETION))
					wait();
				for (int i=0;i<CPU_data_length;i++)
				{
					CPU_data_buffer[i].lower_bytes = CPU_buffer_TLP_up[CPU_buffer_TLP_up_out].data[2*i];
					CPU_data_buffer[i].upper_bytes = CPU_buffer_TLP_up[CPU_buffer_TLP_up_out].data[2*i+1];
				}
				CPU_buffer_TLP_up_out = (CPU_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
				CPU_data_ready = true;
				while (CPU_active)
					wait();
			}
		}
		else if((CPU_write_reguest_completed) && (CPU_write_reguest_completed_time != sc_time_stamp()))
		{
			if (CPU_is_write)
			{
				data = new unsigned[2*CPU_data_length];
				for (int i=0;i<2*CPU_data_length;i++)
					if (i%2 == 0)
						data[i] = CPU_data_buffer[i/2].lower_bytes;
					else
						data[i] = CPU_data_buffer[i/2].upper_bytes;
				delete[] CPU_data_buffer;
				if (CPU_address.high_address == 0x0)
					if (CPU_data_length == 512)
						tlp = construct_TLP_Request_Memory_32(true, MEMORY, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.low_address, data, 0);
					else
						tlp = construct_TLP_Request_Memory_32(true, MEMORY, 0, true, false, false, false, 2*CPU_data_length, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.low_address, data, 0);
				else
					if (CPU_data_length == 512)
						tlp = construct_TLP_Request_Memory_64(true, MEMORY, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.high_address, CPU_address.low_address, data, 0);
					else
						tlp = construct_TLP_Request_Memory_64(true, MEMORY, 0, true, false, false, false, 2*CPU_data_length, id>>8, (id & 0xFF)>>3, id & 0x7, (CPU_tag++)%256, (byte)0xFF, CPU_address.high_address, CPU_address.low_address, data, 0);
				delete[] data;
				while ((CPU_buffer_TLP_down_in+1)%MAX_BUFFER_RC == CPU_buffer_TLP_down_out)
					wait();
				CPU_buffer_TLP_down[CPU_buffer_TLP_down_in] = tlp;
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Target Buffer : CPU" << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
				if (CPU_address.high_address == 0x0)
				{
					for (int i=0; i<3*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						cout << hex << (unsigned)tlp.header[i] << dec << " ";
					}
				}
				else
				{
					for (int i=0; i<4*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						cout << hex << (unsigned)tlp.header[i] << dec << " ";
					}
				}
				cout << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
				if (tlp.length == 0)
				{
					for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((tlp.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((tlp.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((tlp.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (tlp.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				else
				{
					for (int i=0; i<tlp.length*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((tlp.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((tlp.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((tlp.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (tlp.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				cout << endl;
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << tlp.ECRC << dec << endl;
#endif
				CPU_buffer_TLP_down_in = (CPU_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
				CPU_buffer_TLP_down_time = sc_time_stamp();
				wait();
				while((CPU_buffer_TLP_up_in == CPU_buffer_TLP_up_out) || (CPU_buffer_TLP_up_time == sc_time_stamp()) || ((PCIe_TLP_type_t)(CPU_buffer_TLP_up[CPU_buffer_TLP_up_out].header[0] & 0x1F) != COMPLETION))
					wait();
				CPU_buffer_TLP_up_out = (CPU_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
				CPU_write_done = true;
				CPU_write_reguest_completed = false;
			}
		}
		wait();
	}
}

void
PCIe_Root_Complex::CPU_switch_action()
{
	bool is_64bit;
	PCIe_address addr;

	while (true)
	{
		is_64bit = false;
		if ((CPU_buffer_TLP_down_in != CPU_buffer_TLP_down_out) && (CPU_buffer_TLP_down_time != sc_time_stamp()))
		{
			switch ((PCIe_TLP_type_t)(CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[0] & 0x1F))
			{
			case MEMORY:
			case MEMORY_READ_LOCK:
				if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[0] == 0x20 || CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[0] == 0x21 ||
				    CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[0] == 0x60 || CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[0] == 0x61)
					is_64bit = true;
			case I_O:
			case MESSAGE_ADDRESS:
				if (is_64bit)
				{
					addr.high_address = (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[8])<<24) | (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[9])<<16) |
										(((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[10])<<8) | (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[11]));
					addr.low_address = (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[12])<<24) | (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[13])<<16) |
									   (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[14])<<8) | (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[15]));
				}
				else
				{
					addr.high_address = 0x0;
					addr.low_address = (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[8])<<24) | (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[9])<<16) |
									   (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[10])<<8) | (((unsigned)CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[11]));
				}
				switch (decode_address(addr))
				{
				case 0:
				case 1:
				case 2:
				case 6:
					if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
					{
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data;
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].DW4_header;
						int limit;
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header)
						{
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
							limit = 16;
						}
						else
						{
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
							limit = 12;
						}
						for (int i=0;i<limit;i++)
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[i];
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].length;
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
						{
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[1024];
								for (int i=0;i<1024;i++)
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
							}
							else
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length];
								for (int i=0;i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length;i++)
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
							}
						}
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].TLP_digest = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].TLP_digest;
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].ECRC;
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DRAM" << endl;
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Header : ";
						for (int i=0; i<limit ; i++)
						{
							cout.width(2);
							cout.fill('0');
							cout << hex << (unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] << dec << " ";
						}
						cout << endl;
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
						{
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Data : ";
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
							{
								for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							else
							{
								for (int i=0; i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							cout << endl;
						}
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP ECRC : " << hex << DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC << dec << endl;
#endif
						DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DRAM_buffer_TLP_down_time = sc_time_stamp();
						delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header;
						if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data)
							delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data;
						CPU_buffer_TLP_down_out = (CPU_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
					}
					break;
				case 3:
				case 4:
				case 5:
				case 7:
					if ((DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DMI_buffer_TLP_down_out)
					{
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data;
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].DW4_header;
						int limit;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header)
						{
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
							limit = 16;
						}
						else
						{
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
							limit = 12;
						}
						for (int i=0;i<limit;i++)
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[i];
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].length;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
						{
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[1024];
								for (int i=0;i<1024;i++)
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
							}
							else
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length];
								for (int i=0;i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length;i++)
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
							}
						}
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].TLP_digest = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].TLP_digest;
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].ECRC;
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DMI" << endl;
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Header : ";
						for (int i=0; i<limit ; i++)
						{
							cout.width(2);
							cout.fill('0');
							cout << hex << (unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] << dec << " ";
						}
						cout << endl;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
						{
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Data : ";
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
							{
								for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							else
							{
								for (int i=0; i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							cout << endl;
						}
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP ECRC : " << hex << DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC << dec << endl;
#endif
						DMI_buffer_TLP_down_in = (DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DMI_buffer_TLP_down_time = sc_time_stamp();
						delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header;
						if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data)
							delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data;
						CPU_buffer_TLP_down_out = (CPU_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
					}
					break;
				}
				break;
			case CONFIGURATION_TYPE0:
			case CONFIGURATION_TYPE1:
			case COMPLETION:
			case COMPLETION_LOCK:
			case MESSAGE_ID:
			case MESSAGE_BROADCAST:
				if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[8] == 0)
				{
					if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[9] == HOST_DRAM_CONTROLLER_ID)
					{
						if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
						{
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data;
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].DW4_header;
							int limit;
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header)
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[i];
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].length;
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
							{
								if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
								{
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
								}
								else
								{
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length];
									for (int i=0;i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length;i++)
										DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
								}
							}
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].TLP_digest = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].TLP_digest;
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].ECRC;
#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DRAM" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] << dec << " ";
							}
							cout << endl;
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Data : ";
								if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP ECRC : " << hex << DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC << dec << endl;
#endif
							DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_down_time = sc_time_stamp();
							delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header;
							if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data)
								delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data;
							CPU_buffer_TLP_down_out = (CPU_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
						}
					}
					else if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[9] == SATA_CONTROLLER_1_ID || CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[9] == SATA_CONTROLLER_2_ID)
					{
						if ((DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DMI_buffer_TLP_down_out)
						{
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data;
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].DW4_header;
							int limit;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header)
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header[i];
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].length;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
							{
								if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
								{
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
								}
								else
								{
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length];
									for (int i=0;i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length;i++)
										DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data[i];
								}
							}
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].TLP_digest = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].TLP_digest;
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC = CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].ECRC;
#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DMI" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] << dec << " ";
							}
							cout << endl;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Data : ";
								if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP ECRC : " << hex << DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC << dec << endl;
#endif
							DMI_buffer_TLP_down_in = (DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
							DMI_buffer_TLP_down_time = sc_time_stamp();
							delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header;
							if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data)
								delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data;
							CPU_buffer_TLP_down_out = (CPU_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
						}
					}
				}
				break;
			case MESSAGE_RC:
			case MESSAGE_LOCAL:
			case MESSAGE_GATHERED_TO_RC:
				delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].header;
				if (CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].with_data)
					delete[] CPU_buffer_TLP_down[CPU_buffer_TLP_down_out].data;
				CPU_buffer_TLP_down_out = (CPU_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
				break;
			}
		}
		wait();
	}
}

void
PCIe_Root_Complex::DRAM_switch_action()
{
	bool is_64bit;
	PCIe_address addr;

	while (true)
	{
		is_64bit = false;
		if ((DRAM_buffer_TLP_up_in != DRAM_buffer_TLP_up_out) && (DRAM_buffer_TLP_up_time != sc_time_stamp()))
		{
			switch ((PCIe_TLP_type_t)(DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[0] & 0x1F))
			{
			case MEMORY:
			case MEMORY_READ_LOCK:
				if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[0] == 0x20 || DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[0] == 0x21 ||
				    DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[0] == 0x60 || DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[0] == 0x61)
					is_64bit = true;
			case I_O:
			case MESSAGE_ADDRESS:
				if (is_64bit)
				{
					addr.high_address = (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[8])<<24) | (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[9])<<16) |
										(((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[10])<<8) | (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[11]));
					addr.low_address = (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[12])<<24) | (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[13])<<16) |
									   (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[14])<<8) | (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[15]));
				}
				else
				{
					addr.high_address = 0x0;
					addr.low_address = (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[8])<<24) | (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[9])<<16) |
									   (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[10])<<8) | (((unsigned)DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[11]));
				}
				switch (decode_address(addr))
				{
				case 0:
				case 1:
				case 2:
				case 6:
					if ((CPU_buffer_TLP_up_in+1)%MAX_BUFFER_RC != CPU_buffer_TLP_up_out)
					{
						CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data;
						CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].DW4_header = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].DW4_header;
						int limit;
						if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].DW4_header)
						{
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*4];
							limit = 16;
						}
						else
						{
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*3];
							limit = 12;
						}
						for (int i=0;i<limit;i++)
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[i];
						CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].length;
						if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data)
						{
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length == 0)
							{
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data = new unsigned[1024];
								for (int i=0;i<1024;i++)
									CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
							}
							else
							{
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data = new unsigned[CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length];
								for (int i=0;i<CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length;i++)
									CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
							}
						}
						CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].TLP_digest = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].TLP_digest;
						CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].ECRC = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to CPU" << endl;
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "CPU TLP Header : ";
						for (int i=0; i<limit ; i++)
						{
							cout.width(2);
							cout.fill('0');
							cout << hex << (unsigned)CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header[i] << dec << " ";
						}
						cout << endl;
						if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data)
						{
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "CPU TLP Data : ";
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length == 0)
							{
								for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							else
							{
								for (int i=0; i<CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							cout << endl;
						}
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "CPU TLP ECRC : " << hex << CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].ECRC << dec << endl;
#endif
						CPU_buffer_TLP_up_in = (CPU_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
						CPU_buffer_TLP_up_time = sc_time_stamp();
						delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header;
						if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data)
							delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data;
						DRAM_buffer_TLP_up_out = (DRAM_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
					}
					break;
				case 3:
				case 4:
				case 5:
				case 7:
					if ((DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DMI_buffer_TLP_down_out)
					{
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data;
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].DW4_header;
						int limit;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header)
						{
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
							limit = 16;
						}
						else
						{
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
							limit = 12;
						}
						for (int i=0;i<limit;i++)
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[i];
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].length;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
						{
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[1024];
								for (int i=0;i<1024;i++)
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
							}
							else
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length];
								for (int i=0;i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length;i++)
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
							}
						}
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].TLP_digest = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].TLP_digest;
						DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DMI" << endl;
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Header : ";
						for (int i=0; i<limit ; i++)
						{
							cout.width(2);
							cout.fill('0');
							cout << hex << (unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] << dec << " ";
						}
						cout << endl;
						if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
						{
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Data : ";
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
							{
								for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							else
							{
								for (int i=0; i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							cout << endl;
						}
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP ECRC : " << hex << DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC << dec << endl;
#endif
						DMI_buffer_TLP_down_in = (DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DMI_buffer_TLP_down_time = sc_time_stamp();
						delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header;
						if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data)
							delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data;
						DRAM_buffer_TLP_up_out = (DRAM_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
					}
					break;
				}
				break;
			case CONFIGURATION_TYPE0:
			case CONFIGURATION_TYPE1:
			case COMPLETION:
			case COMPLETION_LOCK:
			case MESSAGE_ID:
			case MESSAGE_BROADCAST:
				if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[8] == 0)
				{
					if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[9] == HOST_DRAM_CONTROLLER_ID)
					{
						if ((CPU_buffer_TLP_up_in+1)%MAX_BUFFER_RC != CPU_buffer_TLP_up_out)
						{
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data;
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].DW4_header = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].DW4_header;
							int limit;
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].DW4_header)
							{
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[i];
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].length;
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data)
							{
								if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length == 0)
								{
									CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
								}
								else
								{
									CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data = new unsigned[CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length];
									for (int i=0;i<CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length;i++)
										CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
								}
							}
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].TLP_digest = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].TLP_digest;
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].ECRC = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to CPU" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "CPU TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header[i] << dec << " ";
							}
							cout << endl;
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "CPU TLP Data : ";
								if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "CPU TLP ECRC : " << hex << CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].ECRC << dec << endl;
#endif
							CPU_buffer_TLP_up_in = (CPU_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
							CPU_buffer_TLP_up_time = sc_time_stamp();
							delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header;
							if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data)
								delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data;
							DRAM_buffer_TLP_up_out = (DRAM_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
						}
					}
					else if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[9] == SATA_CONTROLLER_1_ID || DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[9] == SATA_CONTROLLER_2_ID)
					{
						if ((DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DMI_buffer_TLP_down_out)
						{
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data;
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].DW4_header;
							int limit;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].DW4_header)
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[i];
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].length;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
							{
								if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
								{
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
								}
								else
								{
									DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data = new unsigned[DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length];
									for (int i=0;i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length;i++)
										DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
								}
							}
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].TLP_digest = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].TLP_digest;
							DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DMI" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].header[i] << dec << " ";
							}
							cout << endl;
							if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP Data : ";
								if (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI TLP ECRC : " << hex << DMI_buffer_TLP_down[DMI_buffer_TLP_down_in].ECRC << dec << endl;
#endif
							DMI_buffer_TLP_down_in = (DMI_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
							DMI_buffer_TLP_down_time = sc_time_stamp();
							delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header;
							if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data)
								delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data;
							DRAM_buffer_TLP_up_out = (DRAM_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
						}
					}
					else if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header[9] == NORTH_DMA_ID)
					{
						if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data)
						{
							if (North_Main_DMA_enable)
							{
								if (North_Main_DMA_command == 0xCA)
								{
									if (!North_Main_DMA_PRD_fetched)
									{
										North_Main_DMA_base_addr = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0];
										North_Main_DMA_base_cnt = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[1] & 0xFFFF;
										North_Main_DMA_PRD_start_addr.low_address = North_Main_DMA_PRD_start_addr.low_address + 2*4;
										North_Main_DMA_PRD_fetched = true;
										North_Main_DMA_PRD_fetched_time = sc_time_stamp();
//#ifdef	DEBUG_RC
										cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> PRD for North Main-DMA is fetched" << endl;
//#endif
									}
									else if (!North_Main_DMA_buffered)
									{
										North_Main_DMA_buffer = new unsigned[1024];
										for (int i=0;i<1024;i++)
											North_Main_DMA_buffer[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
										North_Main_DMA_buffered = true;
										North_Main_DMA_buffered_time = sc_time_stamp();
									}
									else if (North_Main_DMA_write_check)
									{
										if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0] == 0x1)
										{
											North_Main_DMA_burst_change = true;
											North_Main_DMA_PRD_fetch_commanded = false;
											North_Main_DMA_PRD_fetched = false;
											North_Main_DMA_requested_1st = false;
											North_Main_DMA_requested_2nd = false;
											North_Main_DMA_buffered = false;
											North_Main_DMA_write_check = false;
											if (PRD_current == 0)
											{
												North_Main_DMA_enable = false;
												North_Main_DMA_end = 0x1;
//#ifdef	DEBUG_RC
												cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> North Main-DMA is finished" << endl;
//#endif
											}
										}
										else
										{
											if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
											{
												PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
												DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
												DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
												DRAM_buffer_TLP_down_time = sc_time_stamp();
											}
										}
									}
									else
									{
										cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> These data are not requested." << endl;
										sc_stop();
									}
								}
								else
								{
									if (!North_Main_DMA_buffered)
									{
										North_Main_DMA_buffer = new unsigned[1024];
										for (int i=0;i<1024;i++)
											North_Main_DMA_buffer[i] = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[i];
										North_Main_DMA_buffered = true;
										North_Main_DMA_buffered_time = sc_time_stamp();
									}
									else if (!North_Main_DMA_PRD_fetched)
									{
										North_Main_DMA_base_addr = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0];
										North_Main_DMA_base_cnt = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[1] & 0xFFFF;
										North_Main_DMA_PRD_start_addr.low_address = North_Main_DMA_PRD_start_addr.low_address + 2*4;
										North_Main_DMA_PRD_fetched = true;
										North_Main_DMA_PRD_fetched_time = sc_time_stamp();
//#ifdef	DEBUG_RC
										cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> PRD for North Main-DMA is fetched." << endl;
//#endif
										if (North_SSD_DMA_end_check)
										{
											if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0] == 0x1)
											{
												North_SSD_DMA_end_check = false;
												North_SSD_DMA_end = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0];
											}
											else
											{
												if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
												{
													PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
													DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
													DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
													DRAM_buffer_TLP_down_time = sc_time_stamp();
												}
											}
										}
									}
									else
									{
										if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
										{
											PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
											DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
											DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
											DRAM_buffer_TLP_down_time = sc_time_stamp();
										}
									}
								}
							}
							else
							{
								if (North_SSD_DMA_end_check)
								{
									if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0] == 0x1)
									{
										North_SSD_DMA_end_check = false;
										North_SSD_DMA_end = DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data[0];
									}
									else
									{
										if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
										{
											PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
											DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
											DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
											DRAM_buffer_TLP_down_time = sc_time_stamp();
										}
									}
								}
								else
								{
									cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> These data are not requested." << endl;
									sc_stop();
								}
							}
						}
						else
						{
							if (North_Main_DMA_enable)
							{
								if (North_Main_DMA_command == 0xCA)
								{
									delete[] North_Main_DMA_buffer;
									North_Main_DMA_burst_change = true;
									North_Main_DMA_write_check = true;
									if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
									{
										PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
										DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
										DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
										DRAM_buffer_TLP_down_time = sc_time_stamp();
									}
								}
								else
								{
									North_Main_DMA_PRD_fetch_commanded = false;
									North_Main_DMA_PRD_fetched = false;
									North_Main_DMA_requested_2nd = false;
									North_Main_DMA_buffered = false;
//#ifdef	DEBUG_RC
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Write to Memory complete." << endl;
//#endif
									delete[] North_Main_DMA_buffer;
									if (PRD_current == 0)
									{
										North_Main_DMA_enable = false;
										North_Main_DMA_end = 0x1;
										if (System_type == 3)
										{
//#ifdef	DEBUG_RC
											cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> North Main-DMA is finished...Check North SSD-DMA" << endl;
//#endif
											North_SSD_DMA_end_check = true;
											if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
											{
												PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
												DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
												DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
												DRAM_buffer_TLP_down_time = sc_time_stamp();
											}
										}
										else
										{
//#ifdef	DEBUG_RC
											cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> North Main-DMA is finished." << endl;
//#endif
										}
										North_Main_DMA_burst_change = true;
										North_Main_DMA_write_check = true;
									}
								}
							}
						}
						DRAM_buffer_TLP_up_out = (DRAM_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
						DRAM_buffer_TLP_up_time = sc_time_stamp();
					}
				}
				break;
			case MESSAGE_RC:
			case MESSAGE_LOCAL:
			case MESSAGE_GATHERED_TO_RC:
				delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].header;
				if (DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].with_data)
					delete[] DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_out].data;
				DRAM_buffer_TLP_up_out = (DRAM_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
				break;
			}
		}
		wait();
	}
}

void
PCIe_Root_Complex::DMI_make_action()
{
	PCIe_DLL_TLP dll_tlp;

	while (true)
	{
		if ((DMI_buffer_TLP_down_in != DMI_buffer_TLP_down_out) && ((DMI_buffer_DLL_TLP_down_in+1)%MAX_BUFFER_RC != DMI_buffer_DLL_TLP_down_ack_nak) && (DMI_buffer_TLP_down_time != sc_time_stamp()))
		{
			if (DMI_NAK_sequence_number < DMI_sequence_number)
				break;
			dll_tlp = construct_DLL_TLP(DMI_sequence_number++%4096, DMI_buffer_TLP_down[DMI_buffer_TLP_down_out], 0);
			DMI_NAK_sequence_number++;
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Target Buffer : DMI" << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Sequence Number : " << hex << dll_tlp.sequence_number << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Header : ";
			if (dll_tlp.TLP.DW4_header)
				for (int i=0; i<4*PCIe_DOUBLE_WORD; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)dll_tlp.TLP.header[i] << dec << " ";
				}
			else
				for (int i=0; i<3*PCIe_DOUBLE_WORD; i++)
				{
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)dll_tlp.TLP.header[i] << dec << " ";
				}
			cout << endl;
			if (dll_tlp.TLP.with_data)
			{
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP Data : ";
				if (dll_tlp.TLP.length == 0)
				{
					for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (dll_tlp.TLP.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				else
				{
					for (int i=0; i<dll_tlp.TLP.length*PCIe_DOUBLE_WORD; i++)
					{
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>24) & 0xFF) << dec << " ";
							break;
						case 1:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>16) & 0xFF) << dec << " ";
							break;
						case 2:
							cout << hex << ((dll_tlp.TLP.data[i/4]>>8) & 0xFF) << dec << " ";
							break;
						case 3:
							cout << hex << (dll_tlp.TLP.data[i/4] & 0xFF) << dec << " | ";
							break;
						}
					}
				}
				cout << endl;
			}
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "TLP ECRC : " << hex << dll_tlp.TLP.ECRC << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "LCRC : " << hex << dll_tlp.LCRC << dec << endl;
#endif
			DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_in] = dll_tlp;
			DMI_buffer_TLP_down_out = (DMI_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
			DMI_buffer_DLL_TLP_down_in = (DMI_buffer_DLL_TLP_down_in+1)%MAX_BUFFER_RC;
			DMI_buffer_DLL_TLP_down_time = sc_time_stamp();
		}
		wait();
	}
}

void
PCIe_Root_Complex::DMI_switch_action()
{
	bool is_64bit;
	PCIe_address addr;

	while (true)
	{
		is_64bit = false;
		if ((DMI_buffer_TLP_up_in != DMI_buffer_TLP_up_out) && (DMI_buffer_TLP_up_time != sc_time_stamp()))
		{
			switch ((PCIe_TLP_type_t)(DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[0] & 0x1F))
			{
			case MEMORY:
			case MEMORY_READ_LOCK:
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[0] == 0x20 || DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[0] == 0x21 ||
				    DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[0] == 0x60 || DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[0] == 0x61)
					is_64bit = true;
			case I_O:
			case MESSAGE_ADDRESS:
				if (is_64bit)
				{
					addr.high_address = (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[8])<<24) | (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[9])<<16) |
										(((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[10])<<8) | (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[11]));
					addr.low_address = (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[12])<<24) | (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[13])<<16) |
									   (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[14])<<8) | (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[15]));
				}
				else
				{
					addr.high_address = 0x0;
					addr.low_address = (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[8])<<24) | (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[9])<<16) |
									   (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[10])<<8) | (((unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[11]));
				}
				switch (decode_address(addr))
				{
				case 0:
				case 1:
				case 2:
				case 6:
					if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
					{
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data;
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].DW4_header;
						int limit;
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header)
						{
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
							limit = 16;
						}
						else
						{
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
							limit = 12;
						}
						for (int i=0;i<limit;i++)
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[i];
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].length;
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
						{
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[1024];
								for (int i=0;i<1024;i++)
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data[i];
							}
							else
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length];
								for (int i=0;i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length;i++)
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data[i];
							}
						}
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].TLP_digest = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].TLP_digest;
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DRAM" << endl;
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Header : ";
						for (int i=0; i<limit ; i++)
						{
							cout.width(2);
							cout.fill('0');
							cout << hex << (unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] << dec << " ";
						}
						cout << endl;
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
						{
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Data : ";
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
							{
								for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							else
							{
								for (int i=0; i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
								{
									cout.width(2);
									cout.fill('0');
									switch (i%4)
									{
									case 0:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
										break;
									case 1:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
										break;
									case 2:
										cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
										break;
									case 3:
										cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
										break;
									}
								}
							}
							cout << endl;
						}
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP ECRC : " << hex << DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC << dec << endl;
#endif
						DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DRAM_buffer_TLP_down_time = sc_time_stamp();
						delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header;
						if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data)
							delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data;
						DMI_buffer_TLP_up_out = (DMI_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
					}
					break;
				}
				break;
			case CONFIGURATION_TYPE0:
			case CONFIGURATION_TYPE1:
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[8] == 0)
				{
					if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[9] == HOST_DRAM_CONTROLLER_ID)
					{
						if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
						{
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data;
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].DW4_header;
							int limit;
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].DW4_header)
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[i];
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].length;
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
							{
								if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
								{
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data[i];
								}
								else
								{
									DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data = new unsigned[DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length];
									for (int i=0;i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length;i++)
										DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data[i];
								}
							}
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].TLP_digest = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].TLP_digest;
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to DRAM" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].header[i] << dec << " ";
							}
							cout << endl;
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Data : ";
								if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP ECRC : " << hex << DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in].ECRC << dec << endl;
#endif
							DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_down_time = sc_time_stamp();
							delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header;
							if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data)
								delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data;
							DMI_buffer_TLP_up_out = (DMI_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
						}
					}
				}
				break;
			case COMPLETION:
			case COMPLETION_LOCK:
			case MESSAGE_ID:
			case MESSAGE_BROADCAST:
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[8] == 0)
				{
					if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[9] == HOST_DRAM_CONTROLLER_ID)
					{
						if ((CPU_buffer_TLP_up_in+1)%MAX_BUFFER_RC != CPU_buffer_TLP_up_out)
						{
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data;
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].DW4_header = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].DW4_header;
							int limit;
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].DW4_header)
							{
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*4];
								limit = 16;
							}
							else
							{
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*3];
								limit = 12;
							}
							for (int i=0;i<limit;i++)
								CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[i];
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].length;
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data)
							{
								if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length == 0)
								{
									CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data = new unsigned[1024];
									for (int i=0;i<1024;i++)
										CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data[i];
								}
								else
								{
									CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data = new unsigned[CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length];
									for (int i=0;i<CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length;i++)
										CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i] = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data[i];
								}
							}
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].TLP_digest = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].TLP_digest;
							CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].ECRC = DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].ECRC;
#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Switch to CPU" << endl;
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Header : ";
							for (int i=0; i<limit ; i++)
							{
								cout.width(2);
								cout.fill('0');
								cout << hex << (unsigned)CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].header[i] << dec << " ";
							}
							cout << endl;
							if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].with_data)
							{
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP Data : ";
								if (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length == 0)
								{
									for (int i=0; i<1024*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								else
								{
									for (int i=0; i<CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].length*PCIe_DOUBLE_WORD; i++)
									{
										cout.width(2);
										cout.fill('0');
										switch (i%4)
										{
										case 0:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>24) & 0xFF) << dec << " ";
											break;
										case 1:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>16) & 0xFF) << dec << " ";
											break;
										case 2:
											cout << hex << ((CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4]>>8) & 0xFF) << dec << " ";
											break;
										case 3:
											cout << hex << (CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].data[i/4] & 0xFF) << dec << " | ";
											break;
										}
									}
								}
								cout << endl;
							}
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DRAM TLP ECRC : " << hex << CPU_buffer_TLP_up[CPU_buffer_TLP_up_in].ECRC << dec << endl;
#endif
							CPU_buffer_TLP_up_in = (CPU_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
							CPU_buffer_TLP_up_time = sc_time_stamp();
							delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header;
							if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data)
								delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data;
							DMI_buffer_TLP_up_out = (DMI_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
						}
					}
				}
				break;
			case MESSAGE_RC:
			case MESSAGE_LOCAL:
			case MESSAGE_GATHERED_TO_RC:
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMA Interrupt Message : 0x" << hex << (unsigned)DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[15] << dec << endl;
#endif
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[11])
					South_Main_DMA_end = 0x1;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header[15])
					South_SSD_DMA_end = 0x1;
				delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].header;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].with_data)
					delete[] DMI_buffer_TLP_up[DMI_buffer_TLP_up_out].data;
				DMI_buffer_TLP_up_out = (DMI_buffer_TLP_up_out+1)%MAX_BUFFER_RC;
				break;
			}
		}
		wait();
	}
}

void
PCIe_Root_Complex::DMI_TLP_send_action()
{
	unsigned	wait_cnt;

	DMI_lane = DMI_port.lane_width();

	while(true)
	{
		wait_cnt = 0;
		if ((DMI_buffer_DLL_TLP_down_in != DMI_buffer_DLL_TLP_down_out) && 
			(!DMI_port.is_in_use()) &&
			(DMI_port.check_release_time() != sc_time_stamp()) &&
			((DMI_buffer_DLL_TLP_down_time != sc_time_stamp()) || (DMI_buffer_DLL_TLP_down_in != (DMI_buffer_DLL_TLP_down_out+1)%MAX_BUFFER_RC)) &&
			(arbitrate_port(DMI_port.get_id(),1)))
		{
			if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
			{
				DMI_stop = false;
				continue;
			}
			DMI_port.set_in_use(true);
			DMI_port.PL_send_symbol(STP);
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send STP Symbol to DMI Port." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();
			if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			DMI_port.DLL_send_sequence_number_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].sequence_number>>8));
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send Sequence Number to DMI Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].sequence_number>>8) << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();
			if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			DMI_port.DLL_send_sequence_number_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].sequence_number));
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send Sequence Number to DMI Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].sequence_number << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();
			if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.DW4_header)
			{
				for (int i=0;i<4*PCIe_DOUBLE_WORD;i++)
				{
					DMI_port.TL_send_header_byte(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.header[i]);
#ifdef	DEBUG_RC
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Header to DMI Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.header[i] << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%DMI_lane == 0)
						wait();
					if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
						break;
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}
			else
			{
				for (int i=0;i<3*PCIe_DOUBLE_WORD;i++)
				{
					DMI_port.TL_send_header_byte(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.header[i]);
#ifdef	DEBUG_RC
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Header to DMI Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.header[i] << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%DMI_lane == 0)
						wait();
					if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
						break;
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}

			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.with_data)
			{
				if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.length == 0)
				{
					for (int i=0;i<1024*PCIe_DOUBLE_WORD;i++)
					{
						switch (i%4)
						{
						case 0:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24));
							break;
						case 1:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16));
							break;
						case 2:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8));
							break;
						case 3:
							DMI_port.TL_send_data_byte((byte)DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]);
							break;
						}
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Data to DMI Port : ";
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24) & 0xFF) << dec << "." << endl;
							break;
						case 1:
							cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16) & 0xFF) << dec << "." << endl;
							break;
						case 2:
							cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8) & 0xFF) << dec << "." << endl;
							break;
						case 3:
							cout << hex << (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4] & 0xFF) << dec << "." << endl;
							break;
						}
#endif
						wait_cnt++;
						if (wait_cnt%DMI_lane == 0)
							wait();
						if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
							break;
					}
				}
				else
				{
					for (int i=0;i<DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.length*PCIe_DOUBLE_WORD;i++)
					{
						switch (i%4)
						{
						case 0:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24));
							break;
						case 1:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16));
							break;
						case 2:
							DMI_port.TL_send_data_byte((byte)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8));
							break;
						case 3:
							DMI_port.TL_send_data_byte((byte)DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]);
							break;
						}
#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP Data to DMI Port : ";
						cout.width(2);
						cout.fill('0');
						switch (i%4)
						{
						case 0:
							cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>24) & 0xFF) << dec << "." << endl;
							break;
						case 1:
							cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>16) & 0xFF) << dec << "." << endl;
							break;
						case 2:
							cout << hex << ((DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4]>>8) & 0xFF) << dec << "." << endl;
							break;
						case 3:
							cout << hex << (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.data[i/4] & 0xFF) << dec << "." << endl;
							break;
						}
#endif
						wait_cnt++;
						if (wait_cnt%DMI_lane == 0)
							wait();
						if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
							break;
					}
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}

			if (DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.TLP_digest)
			{
				for (int i=3;i>=0;i--)
				{
					DMI_port.TL_send_ECRC_byte(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.ECRC>>(8*i));
#ifdef	DEBUG_RC
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send TLP ECRC to DMI Port : ";
					cout.width(2);
					cout.fill('0');
					cout << hex << (unsigned)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].TLP.ECRC>>(8*i)) << dec << "." << endl;
#endif
					wait_cnt++;
					if (wait_cnt%DMI_lane == 0)
						wait();
					if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
						break;
				}
				if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
				{
					DMI_stop = false;
					DMI_port.set_in_use(false);
					wait();
					continue;
				}
			}

			for (int i=3;i>=0;i--)
			{
				DMI_port.DLL_send_LCRC_byte(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].LCRC>>(8*i));
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send LCRC to DMI Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)(DMI_buffer_DLL_TLP_down[DMI_buffer_DLL_TLP_down_out].LCRC>>(8*i)) << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%DMI_lane == 0)
					wait();
				if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
					break;
			}
			if ((DMI_stop) && (DMI_buffer_DLLP_up_time != sc_time_stamp()))
			{
				DMI_stop = false;
				DMI_port.set_in_use(false);
				wait();
				continue;
			}

			DMI_port.PL_send_symbol(END);
			DMI_port.set_in_use(false);
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send END Symbol to DMI Port." << endl;
#endif
			DMI_buffer_DLL_TLP_down_out = (DMI_buffer_DLL_TLP_down_out+1)%MAX_BUFFER_RC;
			if (DMI_sequence_number > DMI_NAK_sequence_number)
				DMI_NAK_sequence_number++;
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SEND DLL_TLP to DMI Port Complete!" << endl;
#endif
		}
		wait();
	}
}

void
PCIe_Root_Complex::DMI_ack_nak_action()
{
	PCIe_DLLP dllp;

	while (true)
	{
		if ((DMI_buffer_DLL_TLP_up_in != DMI_buffer_DLL_TLP_up_out) && (DMI_buffer_DLL_TLP_up_time != sc_time_stamp()))
		{
			if (!DMI_is_NAK)
			{
				dllp = construct_DLLP_ACK_NAK(ACK, DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].sequence_number, 0);

				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].with_data = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.with_data;
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].DW4_header = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.DW4_header;
				int limit;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].DW4_header)
				{
					DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*4];
					limit = 16;
				}
				else
				{
					DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header = new byte[PCIe_DOUBLE_WORD*3];
					limit = 12;
				}
				for (int i=0;i<limit;i++)
					DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].header[i] = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.header[i];
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.length;
				if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].with_data)
				{
					if (DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length == 0)
					{
						DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data = new unsigned[1024];
						for (int i=0;i<1024;i++)
							DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i] = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i];
					}
					else
					{
						DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data = new unsigned[DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length];
						for (int i=0;i<DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].length;i++)
							DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].data[i] = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data[i];
					}
				}
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].TLP_digest = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.TLP_digest;
				DMI_buffer_TLP_up[DMI_buffer_TLP_up_in].ECRC = DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.ECRC;

				DMI_buffer_TLP_up_in = (DMI_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
			}
			else
			{
				dllp = construct_DLLP_ACK_NAK(NAK, DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].sequence_number, 0);
			}
			delete[] DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.header;
			if (DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.with_data)
				delete[] DMI_buffer_DLL_TLP_up[DMI_buffer_DLL_TLP_up_out].TLP.data;
			DMI_buffer_DLL_TLP_up_out = (DMI_buffer_DLL_TLP_up_out+1)%MAX_BUFFER_RC;

#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI ack_nak DLLP Type : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (unsigned)dllp.type << dec << endl;
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "DMI ack_nak DLLP Data : ";
			for (int i=0; i<3; i++)
			{
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)dllp.data[i] << dec << " ";
			}
			cout << endl;
#endif
			DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_in] = dllp;
			DMI_buffer_DLLP_down_in = (DMI_buffer_DLLP_down_in+1)%MAX_BUFFER_RC;
			DMI_buffer_DLLP_down_time = sc_time_stamp();
		}
		wait();
	}
}

void
PCIe_Root_Complex::DMI_DLLP_send_action()
{
	unsigned wait_cnt;

	DMI_lane = DMI_port.lane_width();

	while (true)
	{
		wait_cnt = 0;
		if ((DMI_buffer_DLLP_down_in != DMI_buffer_DLLP_down_out) &&
			(!DMI_port.is_in_use()) &&
			(DMI_port.check_release_time() != sc_time_stamp()) &&
			((DMI_buffer_DLLP_down_time != sc_time_stamp()) || (DMI_buffer_DLLP_down_in != (DMI_buffer_DLLP_down_out+1)%MAX_BUFFER_RC)) &&
			(arbitrate_port(DMI_port.get_id(),0)))
		{
			DMI_port.set_in_use(true);
			DMI_port.PL_send_symbol(SDP);
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send SDP Symbol to DMI Port." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();

			DMI_port.DLL_send_type_byte((byte)DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_out].type);
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send DLLP Type to DMI Port : ";
			cout.width(2);
			cout.fill('0');
			cout << hex << (unsigned)DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_out].type << dec << "." << endl;
#endif
			wait_cnt++;
			if (wait_cnt%DMI_lane == 0)
				wait();

			for (int i=0; i<3; i++)
			{
				DMI_port.DLL_send_data_byte(DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_out].data[i]);
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send DLLP Data to DMI Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_out].data[i] << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%DMI_lane == 0)
					wait();
			}
			for (int i=1; i>=0; i--)
			{
				DMI_port.DLL_send_CRC_byte(DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_out].CRC>>8*i);
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send CRC to DMI Port : ";
				cout.width(2);
				cout.fill('0');
				cout << hex << (unsigned)(DMI_buffer_DLLP_down[DMI_buffer_DLLP_down_out].CRC>>8*i) << dec << "." << endl;
#endif
				wait_cnt++;
				if (wait_cnt%DMI_lane == 0)
					wait();
			}

			DMI_port.PL_send_symbol(END);
			DMI_port.set_in_use(false);
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Send END Symbol to DMI Port." << endl;
#endif
			DMI_buffer_DLLP_down_out = (DMI_buffer_DLLP_down_out+1)%MAX_BUFFER_RC;
#ifdef	DEBUG_RC
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "SEND DLLP to DMI Port Complete!" << endl;
#endif
		}
		wait();
	}
}

void
PCIe_Root_Complex::DRAM_refresh_count_action()
{
	while (true)
	{
		if (DRAM_refresh_cnt == 0)
		{
			DRAM_refresh_enable = true;
			DRAM_refresh_enable_time = sc_time_stamp();
		}
		else
		{
			if(DRAM_refresh_cnt == DDR_DEFAULT_tRCD+DDR_DEFAULT_CL+DDR_DEFAULT_BURST_LENGTH+DDR_DEFAULT_tRP)
			{
#ifdef	DEBUG_RC
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Stop North SSD-DMA...Refresh Counter : " << DRAM_refresh_cnt << endl;
#endif
				North_SSD_DMA_stop = true;
			}
			DRAM_refresh_cnt--;
		}
		wait();
	}
}

void
PCIe_Root_Complex::DRAM_timing_control_action()
{
	const unsigned DRAM_tRCD = DDR_DEFAULT_tRCD;
	const unsigned DRAM_CL = DDR_DEFAULT_CL;
	const unsigned DRAM_BL = DDR_DEFAULT_BURST_LENGTH;
	const unsigned DRAM_tDQSS = DDR_DEFAULT_tDQSS;
	const unsigned DRAM_tWR = DDR_DEFAULT_tWR;
	const unsigned DRAM_tRP = DDR_DEFAULT_tRP;
	const unsigned DRAM_tRFC = DDR_DEFAULT_tRFC;

	unsigned tRFC_cnt = DRAM_tRFC;

	unsigned DRAM_rank_num = pow(2, DRAM_rank_index);
	unsigned DRAM_bank_num = pow(2, DRAM_bank_index);

	SDRAM_bank_interleave_state_t DRAM_curr_state = IDLE_STATE;

	unsigned* data;
	unsigned full_data_length;
	SDRAM_DDR_data_t SDRAM_current_data;
	unsigned full_banks_num;
	unsigned remained_banks_num;
	unsigned row_activate_cnt;
	unsigned start_bank;
	unsigned end_bank;

	SDRAM_DDR_bank_control_info_t* bank_manager;

	bool command_sent;
	bool data_reserved;

	PCIe_address addr;
	PCIe_TLP tlp;

	while (true)
	{
		int bank_cnt;

		switch(DRAM_curr_state)
		{
		case IDLE_STATE:
			if ((DRAM_refresh_enable) && (DRAM_CLK == true))
			{
#ifdef	DEBUG_RC_SDRAM_CTRL
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Start Auto Refresh." << endl;
#endif
				DPDRAM_port->SDRAM_refresh(0, false);
				DRAM_curr_state = REFRESH_STATE;
#ifdef	DEBUG_RC_SDRAM_CTRL
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Now Refreshing..." << tRFC_cnt << endl;
#endif
				tRFC_cnt--;
			}
			else if ((DRAM_buffer_TLP_down_in != DRAM_buffer_TLP_down_out) &&
				((DRAM_buffer_TLP_down_time != sc_time_stamp()) || (DRAM_buffer_TLP_down_in != (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC)) &&
				(DRAM_CLK == true))
			{
				addr.high_address = 0x0;
				addr.low_address = (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[8])<<24) | (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[9])<<16) |
								   (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[10])<<8) | (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[11]));
				if ((addr.high_address == system_address_map[0].start_addr.low_address) && (addr.low_address <= system_address_map[2].end_addr.low_address))
				{
					if (addr.low_address <= system_address_map[0].end_addr.low_address/2)
					{
						if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length != 0)
						{
							if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length%(DRAM_BL*((DDR_EXT_BITWIDTH_MODULE/8)/4)) == 0)
								full_data_length = DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length;
							else
								full_data_length = DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length + ((DRAM_BL*((DDR_EXT_BITWIDTH_MODULE/8)/4))-DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length%(DRAM_BL*((DDR_EXT_BITWIDTH_MODULE/8)/4)));
						}
						else
						{
							full_data_length = 1024;
						}
						full_banks_num = remained_banks_num = full_data_length / (DRAM_BL*(DDR_EXT_BITWIDTH_MODULE/8)/4);
						row_activate_cnt = 0;
						start_bank = (addr.low_address >> 5) & 0x7;
						end_bank = ((((addr.low_address + full_data_length*4) >> 5) & 0x7) - 1) % (DRAM_rank_num*DRAM_bank_num);
						bank_manager = new SDRAM_DDR_bank_control_info_t[DRAM_rank_num*DRAM_bank_num];
						for (int i=0;i<DRAM_rank_num*DRAM_bank_num;i++)
						{
							bank_manager[i].bank_curr_state = SDRAM_IDLE;
							bank_manager[i].tRCD_cnt = DRAM_tRCD;
							bank_manager[i].CL_cnt = DRAM_CL;
							bank_manager[i].read_data_enable = false;
							bank_manager[i].BL_cnt = DRAM_BL;
							bank_manager[i].read_auto_precharge_cnt = DRAM_BL;
							bank_manager[i].tDQSS_cnt = DRAM_tDQSS;
							bank_manager[i].tWR_cnt = DRAM_tWR;
							bank_manager[i].tRP_cnt = DRAM_tRP;
							if ((full_banks_num%(DRAM_rank_num*DRAM_bank_num) == 0) && (start_bank == 0))
							{
								bank_manager[i].bank_addr = new SDRAM_addr_t[full_banks_num/(DRAM_rank_num*DRAM_bank_num)];
								bank_manager[i].bank_last = full_banks_num/(DRAM_rank_num*DRAM_bank_num)-1;
							}
							else if (start_bank <= end_bank)
							{
								bank_manager[i].bank_addr = new SDRAM_addr_t[full_banks_num/(DRAM_rank_num*DRAM_bank_num)+1];
								bank_manager[i].bank_last = full_banks_num/(DRAM_rank_num*DRAM_bank_num);
							}
							else
							{
								if (end_bank+1 == start_bank)
								{
									bank_manager[i].bank_addr = new SDRAM_addr_t[full_banks_num/(DRAM_rank_num*DRAM_bank_num)+1];
									bank_manager[i].bank_last = full_banks_num/(DRAM_rank_num*DRAM_bank_num);
								}
								else
								{
									bank_manager[i].bank_addr = new SDRAM_addr_t[full_banks_num/(DRAM_rank_num*DRAM_bank_num)+2];
									bank_manager[i].bank_last = full_banks_num/(DRAM_rank_num*DRAM_bank_num)+1;
								}
							}
							bank_manager[i].bank_first = 0;
						}
						unsigned addr_line = 0;
						for (int i=0;i<full_banks_num;i++)
						{
							if ((i != 0) && ((start_bank+i)%(DRAM_rank_num*DRAM_bank_num) == 0))
								addr_line++;
							bank_manager[(start_bank+i)%(DRAM_rank_num*DRAM_bank_num)].bank_addr[addr_line] = addr.low_address + 0x20 * i;
						}
						for (int i=0;i<start_bank;i++)
							bank_manager[i].bank_first++;
						if (end_bank < DRAM_rank_num*DRAM_bank_num-1)
						{
							for (int i=end_bank+1;i<DRAM_rank_num*DRAM_bank_num;i++)
							{
								if (bank_manager[i].bank_last !=0)
									bank_manager[i].bank_last--;
								else
									bank_manager[i].bank_first++;
							}
						}
						if ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[0] >> 6) & 0x1)
						{
							DRAM_curr_state = WRITE_STATE;
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Start Write to DRAM port" << endl;
#endif
						}
						else
						{
							DRAM_curr_state = READ_STATE;
							data = new unsigned[full_data_length];
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Start Read to DRAM port" << endl;
#endif
						}
						data_reserved = false;
					}
					else if ((addr.low_address >= system_address_map[1].start_addr.low_address) && (addr.low_address >= system_address_map[1].end_addr.low_address/2))
					{
						if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out)
						{
							tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
							DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
							DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_up_time = sc_time_stamp();
						}
					}
 					else if ((addr.low_address >= system_address_map[2].start_addr.low_address) && (addr.low_address >= system_address_map[2].end_addr.low_address/2))
					{
/*
#ifdef	DEBUG_RC_SDRAM_CTRL
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> MRS commanded : 0xA62 (burst_length = 4)" << endl;
#endif
						DPDRAM_port->SDRAM_DDR_mode_register_set(0, 0, 0xA62);
						DRAM_curr_state = EMRS_STATE;
*/
						if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out)
						{
							tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
							DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
							DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_up_time = sc_time_stamp();
						}
					}
				}
			}
			break;
		case READ_STATE:
			command_sent = false;
			bank_cnt = 0;
			for (int i=start_bank;bank_cnt<8;i=(i+1)%(DRAM_rank_num*DRAM_bank_num))
			{
				if (bank_manager[i].bank_first<=bank_manager[i].bank_last)
				{
					unsigned rank_sel = (bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 5) & 0x1;
					unsigned bank_sel = (bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 6) & 0x3;
					SDRAM_addr_t row_addr = (bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 16) & 0x1FFF;
					SDRAM_addr_t col_addr = ((bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 6) & 0x3FC) | ((bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 3) & 0x3);
					switch (bank_manager[i].bank_curr_state)
					{
					case SDRAM_IDLE:
						if ((DRAM_CLK == true) && (!command_sent) && (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) == 'Z'))
						{
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Row Activate at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Row=0x" << row_addr << dec << endl;
#endif
							DPDRAM_port->SDRAM_row_activate(0, rank_sel, bank_sel, row_addr);
							command_sent = true;
							row_activate_cnt++;
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Row Activate...tRCD count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRCD_cnt << endl;
#endif
							bank_manager[i].bank_curr_state = SDRAM_ROW_ACT;
							bank_manager[i].tRCD_cnt--;
						}
						break;
					case SDRAM_ROW_ACT:
						if (DRAM_CLK == true)
						{
							if (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) != 'Z')
							{
								bank_manager[i].bank_curr_state = SDRAM_IDLE;
								row_activate_cnt--;
								bank_manager[i].tRCD_cnt++;
							}
							else
							{
#ifdef	DEBUG_RC_SDRAM_CTRL
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Row Activate...tRCD count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRCD_cnt << endl;
#endif
								bank_manager[i].tRCD_cnt--;
								if (bank_manager[i].tRCD_cnt == 0)
								{
									bank_manager[i].bank_curr_state = SDRAM_READ_AP;
									bank_manager[i].tRCD_cnt = DRAM_tRCD;
								}
							}
						}
						break;
					case SDRAM_READ_AP:
						if (bank_manager[i].CL_cnt == DRAM_CL)
						{
							if ((DRAM_CLK == true) && (!command_sent) && (!data_reserved))
							{
//								if (((remained_banks_num < DRAM_rank_num*DRAM_bank_num) && (row_activate_cnt >= remained_banks_num)) ||
//									((remained_banks_num >= DRAM_rank_num*DRAM_bank_num) && (row_activate_cnt == DRAM_rank_num*DRAM_bank_num)))
//								{
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Read Command at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Col=0x" << col_addr << dec << endl;
#endif
									DPDRAM_port->SDRAM_read_command(0, rank_sel, bank_sel, col_addr, true);
									command_sent = true;
									data_reserved = true;
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting CAS Latency...CL count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].CL_cnt << endl;
#endif
									bank_manager[i].CL_cnt--;
									bank_manager[i].read_auto_precharge_cnt--;
//								}
							}
						}
						else if (bank_manager[i].CL_cnt != 0)
						{
							if (DRAM_CLK == true)
							{
#ifdef	DEBUG_RC_SDRAM_CTRL
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting CAS Latency...CL count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].CL_cnt << endl;
#endif
								bank_manager[i].CL_cnt--;
							}
							if (bank_manager[i].read_auto_precharge_cnt != 0)
							{
								bank_manager[i].read_auto_precharge_cnt--;
								if (bank_manager[i].read_auto_precharge_cnt == 0)
									data_reserved = false;
							}
							else if ((DRAM_CLK == true) && (bank_manager[i].tRP_cnt != 0))
							{
#ifdef	DEBUG_RC_SDRAM_CTRL
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRP_cnt << endl;
#endif
								bank_manager[i].tRP_cnt--;
							}
						}
						else
						{
							if (bank_manager[i].read_auto_precharge_cnt != 0)
							{
								bank_manager[i].read_auto_precharge_cnt--;
								if (bank_manager[i].read_auto_precharge_cnt == 0)
									data_reserved = false;
							}
							else if ((DRAM_CLK == true) && (bank_manager[i].tRP_cnt != 0))
							{
#ifdef	DEBUG_RC_SDRAM_CTRL
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRP_cnt << endl;
#endif
								bank_manager[i].tRP_cnt--;
							}
							if (bank_manager[i].read_data_enable)
							{
								if (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) != 'Z')
								{
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Before Read data : 0x" << hex << SDRAM_current_data.upper_bytes << " | 0x" << SDRAM_current_data.lower_bytes << dec;
#endif
									SDRAM_current_data = DPDRAM_port->SDRAM_DDR_read_data(0, rank_sel, bank_sel, DDR_DEFAULT_BURST_LENGTH-bank_manager[i].BL_cnt, false);
									data[(bank_manager[i].bank_addr[bank_manager[i].bank_first]-addr.low_address)/4+2*(DRAM_BL-bank_manager[i].BL_cnt)] = SDRAM_current_data.lower_bytes;
									data[(bank_manager[i].bank_addr[bank_manager[i].bank_first]-addr.low_address)/4+2*(DRAM_BL-bank_manager[i].BL_cnt)+1] = SDRAM_current_data.upper_bytes;
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << ", After Read data : 0x" << hex << SDRAM_current_data.upper_bytes << " | 0x" << SDRAM_current_data.lower_bytes << dec << endl;
#endif
									bank_manager[i].BL_cnt--;
									if (bank_manager[i].BL_cnt == 0)
									{
										bank_manager[i].CL_cnt = DRAM_CL;
										bank_manager[i].read_data_enable = false;
										bank_manager[i].BL_cnt = DRAM_BL;
										bank_manager[i].read_auto_precharge_cnt = DRAM_BL;
										if (bank_manager[i].tRP_cnt != 0)
										{
											bank_manager[i].bank_curr_state = SDRAM_PRECHARGE;
#ifdef	DEBUG_RC_SDRAM_CTRL
											cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRP_cnt << endl;
#endif
											bank_manager[i].tRP_cnt--;
										}
										else
										{
											if (i == start_bank)
												start_bank = (start_bank+1)%(DRAM_rank_num*DRAM_bank_num);
											bank_manager[i].bank_first++;
											bank_manager[i].bank_curr_state=SDRAM_IDLE;
											bank_manager[i].tRP_cnt = DRAM_tRP;
											remained_banks_num--;
											if (bank_manager[i].bank_first<=bank_manager[i].bank_last)
												row_activate_cnt--;
											if (remained_banks_num == 0)
											{
												unsigned data_finished = 0;
												for (int j=0;j<DRAM_rank_num*DRAM_bank_num;j++)
													if ((bank_manager[j].bank_curr_state == SDRAM_IDLE) && (bank_manager[j].bank_first>bank_manager[j].bank_last))
														data_finished++;
												if ((data_finished == DRAM_rank_num*DRAM_bank_num) && ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out))
												{
													if (full_data_length == 1024)
														tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
													else
														if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length < DRAM_BL * ((DDR_EXT_BITWIDTH_MODULE/8) / 4))
															tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
														else
															tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, full_data_length, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
													delete[] data;
													DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
													DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
													DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
													DRAM_buffer_TLP_up_time = sc_time_stamp();
													DRAM_curr_state = IDLE_STATE;
												}
											}
										}
									}
								}
							}
							else
							{
								bank_manager[i].read_data_enable = true;
							}
						}
						break;
					case SDRAM_PRECHARGE:
						if (DRAM_CLK == true)
						{
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRP_cnt << endl;
#endif
							if (bank_manager[i].tRP_cnt != 0)
								bank_manager[i].tRP_cnt--;
							if(bank_manager[i].tRP_cnt == 0)
							{
								if (i == start_bank)
									start_bank = (start_bank+1)%(DRAM_rank_num*DRAM_bank_num);
								bank_manager[i].bank_first++;
								bank_manager[i].bank_curr_state=SDRAM_IDLE;
								bank_manager[i].tRP_cnt = DRAM_tRP;
								remained_banks_num--;
								if (bank_manager[i].bank_first<=bank_manager[i].bank_last)
									row_activate_cnt--;
								if (remained_banks_num == 0)
								{
									unsigned data_finished = 0;
									for (int j=0;j<DRAM_rank_num*DRAM_bank_num;j++)
										if ((bank_manager[j].bank_curr_state == SDRAM_IDLE) && (bank_manager[j].bank_first>bank_manager[j].bank_last))
											data_finished++;
									if ((data_finished == DRAM_rank_num*DRAM_bank_num) && ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out))
									{
										if (full_data_length == 1024)
											tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
										else
											if (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length < DRAM_BL * ((DDR_EXT_BITWIDTH_MODULE/8) / 4))
												tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
											else
												tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, full_data_length, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
										delete[] data;
										DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
										DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
										DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
										DRAM_buffer_TLP_up_time = sc_time_stamp();
										DRAM_curr_state = IDLE_STATE;
									}
								}
							}
						}
						break;
					default:
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unknown State!" << endl << flush;
						sc_stop();
					}
				}
				bank_cnt++;
			}
			break;
		case WRITE_STATE:
			command_sent = false;
			bank_cnt = 0;
			for (int i=start_bank;bank_cnt<8;i=(i+1)%(DRAM_rank_num*DRAM_bank_num))
			{
				if (bank_manager[i].bank_first<=bank_manager[i].bank_last)
				{
					unsigned rank_sel = (bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 5) & 0x1;
					unsigned bank_sel = (bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 6) & 0x3;
					SDRAM_addr_t row_addr = (bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 16) & 0x1FFF;
					SDRAM_addr_t col_addr = ((bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 6) & 0x3FC) | ((bank_manager[i].bank_addr[bank_manager[i].bank_first] >> 3) & 0x3);
					switch (bank_manager[i].bank_curr_state)
					{
					case SDRAM_IDLE:
						if ((DRAM_CLK == true) && (!command_sent) && (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) == 'Z'))
						{
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Row Activate at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Row=0x" << row_addr << dec << endl;
#endif
							DPDRAM_port->SDRAM_row_activate(0, rank_sel, bank_sel, row_addr);
							command_sent = true;
							row_activate_cnt++;
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Row Activate...tRCD count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRCD_cnt << endl;
#endif
							bank_manager[i].bank_curr_state = SDRAM_ROW_ACT;
							bank_manager[i].tRCD_cnt--;
						}
						break;
					case SDRAM_ROW_ACT:
						if (DRAM_CLK == true)
						{
							if (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) != 'Z')
							{
								bank_manager[i].bank_curr_state = SDRAM_IDLE;
								row_activate_cnt--;
								bank_manager[i].tRCD_cnt++;
							}
							else
							{
#ifdef	DEBUG_RC_SDRAM_CTRL
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Row Activate...tRCD count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRCD_cnt << endl;
#endif
								bank_manager[i].tRCD_cnt--;
								if (bank_manager[i].tRCD_cnt == 0)
								{
									bank_manager[i].bank_curr_state = SDRAM_WRITE_AP;
									bank_manager[i].tRCD_cnt = DRAM_tRCD;
								}
							}
						}
						break;
					case SDRAM_WRITE_AP:
						if (bank_manager[i].tDQSS_cnt == DRAM_tDQSS)
						{
							if ((DRAM_CLK == true) && (!command_sent) && (!data_reserved))
							{
//								if (((remained_banks_num < DRAM_rank_num*DRAM_bank_num) && (row_activate_cnt >= remained_banks_num)) ||
//									((remained_banks_num >= DRAM_rank_num*DRAM_bank_num) && (row_activate_cnt == DRAM_rank_num*DRAM_bank_num)))
//								{
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Write Command at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Col=0x" << col_addr << dec << endl;
#endif
									DPDRAM_port->SDRAM_write_command(0, rank_sel, bank_sel, col_addr, true);
									if (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) == 'Z')
									{
										DPDRAM_port->SDRAM_DDR_set_DQS(0, rank_sel, bank_sel, sc_logic('0'));
									}
									else
									{
										cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> DQS signal is not valid." << endl;
										sc_stop();
									}
									command_sent = true;
									data_reserved = true;
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting DQS Transition...tDQSS count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tDQSS_cnt << endl;
#endif
									bank_manager[i].tDQSS_cnt--;
//								}
							}
						}
						else
						{
							if (bank_manager[i].tDQSS_cnt != 0)
							{
#ifdef	DEBUG_RC_SDRAM_CTRL
								cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting DQS Transition...tDQSS count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tDQSS_cnt << endl;
#endif
								bank_manager[i].tDQSS_cnt--;
							}
							else
							{
								if (bank_manager[i].BL_cnt != 0)
								{
									if ((bank_manager[i].bank_addr[bank_manager[i].bank_first]-addr.low_address)/4+2*(DRAM_BL-bank_manager[i].BL_cnt) < DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].length)
									{
										SDRAM_current_data.lower_bytes = DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].data[(bank_manager[i].bank_addr[bank_manager[i].bank_first]-addr.low_address)/4+2*(DRAM_BL-bank_manager[i].BL_cnt)];
										SDRAM_current_data.upper_bytes = DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].data[(bank_manager[i].bank_addr[bank_manager[i].bank_first]-addr.low_address)/4+2*(DRAM_BL-bank_manager[i].BL_cnt)+1];
									}
#ifdef	DEBUG_RC_SDRAM_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Write data : 0x" << hex << SDRAM_current_data.upper_bytes << " | 0x" << SDRAM_current_data.lower_bytes << dec << endl;
#endif
									DPDRAM_port->SDRAM_DDR_write_data(0, rank_sel, bank_sel, DDR_DEFAULT_BURST_LENGTH-bank_manager[i].BL_cnt, SDRAM_current_data, false);
									if (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) == '0')
									{
										DPDRAM_port->SDRAM_DDR_set_DQS(0, rank_sel, bank_sel, sc_logic('1'));
									}
									else if (DPDRAM_port->SDRAM_DDR_get_DQS(0, rank_sel, bank_sel) == '1')
									{
										DPDRAM_port->SDRAM_DDR_set_DQS(0, rank_sel, bank_sel, sc_logic('0'));
									}
									else
									{
										cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> DQS signal is not valid." << endl;
										sc_stop();
									}
									bank_manager[i].BL_cnt--;
									if (bank_manager[i].BL_cnt == 0)
									{
										DPDRAM_port->SDRAM_DDR_set_DQS(0, rank_sel, bank_sel, sc_logic('Z'));
										data_reserved = false;
									}
								}
								if ((bank_manager[i].BL_cnt == 0) && (DRAM_CLK == true))
								{
									if (bank_manager[i].tWR_cnt != 0)
									{
#ifdef	DEBUG_RC_SDRAM_CTRL
										cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tWR count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tWR_cnt << endl;
#endif
										bank_manager[i].tWR_cnt--;
									}
									else
									{
										bank_manager[i].bank_curr_state= SDRAM_PRECHARGE;
										bank_manager[i].BL_cnt = DRAM_BL;
										bank_manager[i].tDQSS_cnt = DRAM_tDQSS;
										bank_manager[i].tWR_cnt = DRAM_tWR;
#ifdef	DEBUG_RC_SDRAM_CTRL
										cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRP_cnt << endl;
#endif
										bank_manager[i].tRP_cnt--;
									}
								}
							}
						}
						break;
					case SDRAM_PRECHARGE:
						if (DRAM_CLK == true)
						{
#ifdef	DEBUG_RC_SDRAM_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count(" << rank_sel << ", " << bank_sel << ") : " << bank_manager[i].tRP_cnt << endl;
#endif
							bank_manager[i].tRP_cnt--;
							if(bank_manager[i].tRP_cnt==0)
							{
								if (i == start_bank)
									start_bank = (start_bank+1)%(DRAM_rank_num*DRAM_bank_num);
								bank_manager[i].bank_first++;
								bank_manager[i].bank_curr_state=SDRAM_IDLE;
								bank_manager[i].tRP_cnt = DRAM_tRP;
								remained_banks_num--;
								if (bank_manager[i].bank_first<=bank_manager[i].bank_last)
									row_activate_cnt--;
								if (remained_banks_num == 0)
								{
									unsigned data_finished = 0;
									for (int j=0;j<DRAM_rank_num*DRAM_bank_num;j++)
										if ((bank_manager[j].bank_curr_state == SDRAM_IDLE) && (bank_manager[j].bank_first>bank_manager[j].bank_last))
											data_finished++;
									if ((data_finished == DRAM_rank_num*DRAM_bank_num) && ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out))
									{
										tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
										DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
										DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
										DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
										DRAM_buffer_TLP_up_time = sc_time_stamp();
										DRAM_curr_state = IDLE_STATE;
									}
								}
							}
						}
						break;
					default:
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unknown State!" << endl << flush;
						sc_stop();
					}
				}
				bank_cnt++;
			}
			break;
		case EMRS_STATE:
			if (DRAM_CLK == true)
				DRAM_curr_state = IDLE_STATE;
			break;
		case REFRESH_STATE:
			if (DRAM_CLK == true)
			{
#ifdef	DEBUG_RC_SDRAM_CTRL
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Now Refreshing..." << tRFC_cnt << endl;
#endif
				tRFC_cnt--;
				if (tRFC_cnt == 0)
				{
					DRAM_refresh_enable = false;
					DRAM_refresh_cnt = DDR_DEFAULT_tRFCI-(DDR_DEFAULT_tRCD+DDR_DEFAULT_CL+DDR_DEFAULT_BURST_LENGTH+DDR_DEFAULT_tRP);
					North_SSD_DMA_stop = false;
					DRAM_curr_state = IDLE_STATE;
					tRFC_cnt = DRAM_tRFC;
				}
			}
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unknown State!" << endl << flush;
			sc_stop();
		}
		wait();
	}
}

void
PCIe_Root_Complex::SSD_timing_control_action()
{
	const unsigned SSD_tRCD = 1;
	unsigned SSD_CL = 1+(1024/2)/2;
	unsigned SSD_BL = 1024/2;
	if (System_type == 3)
	{
		SSD_CL = 1;
		SSD_BL = DDR_DEFAULT_BURST_LENGTH;
	}
	const unsigned SSD_tDQSS = 1;
	const unsigned SSD_tWR = 1;
	const unsigned SSD_tRP = 1;

	SDRAM_state_t SSD_curr_state = SDRAM_IDLE;

	unsigned rank_sel = 0;
	unsigned bank_sel = 0;
	SDRAM_addr_t row_addr = 0;
	SDRAM_addr_t col_addr;

	bool SSD_is_Write;

	SDRAM_addr_t SDRAM_current_col_addr;
	SDRAM_DDR_data_t SDRAM_current_data;
	unsigned* data;
	unsigned full_data_length = 1024;
	unsigned remained_data_length = 1024;
	bool packet_resolved = false;

	unsigned tRCD_cnt = SSD_tRCD;
	unsigned CL_cnt = SSD_CL;
	unsigned BL_cnt = SSD_BL;
	unsigned tDQSS_cnt = SSD_tDQSS;
	unsigned tWR_cnt = SSD_tWR;
	unsigned tRP_cnt = SSD_tRP;

	PCIe_TLP tlp;
	PCIe_address addr;

	while (true)
	{
		switch(SSD_curr_state)
		{
		case SDRAM_POWER_ON:
			SSD_curr_state = SDRAM_IDLE;
			break;
		case SDRAM_IDLE:
			if (DRAM_CLK == true)
			{
				if (North_Main_DMA_burst_change)
				{
					if (!North_Main_DMA_write_check)
					{
#ifdef	DEBUG_RC_SSD_CTRL
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> MRS commanded : 0xA60 (burst_length = 512)" << endl;
#endif
						SSD_port->SDRAM_DDR_mode_register_set(0, 0xA60);
						SSD_CL = 1+(1024/2)/2;
						SSD_BL = 1024/2;
					}
					else
					{
#ifdef	DEBUG_RC_SSD_CTRL
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> MRS commanded : 0xA62 (burst_length = 4)" << endl;
#endif
						SSD_port->SDRAM_DDR_mode_register_set(0, 0xA62);
						SSD_CL = 1;
						SSD_BL = DDR_DEFAULT_BURST_LENGTH;
					}
					CL_cnt = SSD_CL;
					BL_cnt = SSD_BL;
					SSD_curr_state = SDRAM_MRS;
					North_Main_DMA_burst_change = false;
				}
				else if ((DRAM_buffer_TLP_down_in != DRAM_buffer_TLP_down_out) &&
					((DRAM_buffer_TLP_down_time != sc_time_stamp()) || (DRAM_buffer_TLP_down_in != (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC)))
				{
					addr.high_address = 0x0;
					addr.low_address = (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[8])<<24) | (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[9])<<16) |
									   (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[10])<<8) | (((unsigned)DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[11]));
					if ((addr.high_address == system_address_map[0].start_addr.low_address) && (addr.low_address <= system_address_map[2].end_addr.low_address))
					{
						if (((addr.low_address >= system_address_map[0].end_addr.low_address/2+1) && (addr.low_address <= system_address_map[0].end_addr.low_address)) && (remained_data_length != 0))
						{
							if (addr.low_address >= North_Main_DMA_check_reg_start_addr.low_address)
							{
								if ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[0] >> 6) & 0x1)
								{
									if (North_SSD_DMA_stop)
										break;
									North_Main_DMA_command = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[0];
									North_Main_DMA_sector_cnt = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[1];
									North_Main_DMA_LBA = North_Main_DMA_LBA_current = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[2];
									North_Main_DMA_PRD_length = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[3];
									North_Main_DMA_end = 0x0;
									if (System_type == 3)
									{
										North_SSD_DMA_command = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[4];
										North_SSD_DMA_sector_cnt = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[5];  
										North_SSD_DMA_LBA = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[6];
										North_SSD_DMA_PRD_length = DRAM_buffer_TLP_down[(DRAM_buffer_TLP_down_in-1)%MAX_BUFFER_RC].data[7];
										North_SSD_DMA_end = 0x0;
									}
									PRD_current = North_Main_DMA_sector_cnt/(4096/512);
									if (North_Main_DMA_command == 0x00)
									{
										North_Main_DMA_end = 0x1;
										if (System_type == 3)
										{
#ifdef	DEBUG_RC_SSD_CTRL
											cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> North Main-DMA is disabled...Check North SSD-DMA" << endl;
#endif
											North_SSD_DMA_end_check = true;
											if ((DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_down_out)
											{
												PCIe_TLP tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 1, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, (byte)0xFF, North_Main_DMA_check_reg_start_addr.low_address, NULL, 0);
												DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
												DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
												DRAM_buffer_TLP_down_time = sc_time_stamp();
											}
										}
									}
									else
									{
										North_Main_DMA_enable = true;
										North_Main_DMA_enable_time = sc_time_stamp();
//#ifdef	DEBUG_RC_SSD_CTRL
										cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Write to North Main-DMA registers is finished...North Main-DMA is enabled." <<endl;
//#endif
										if (System_type == 3)
											North_Main_DMA_burst_change = true;
									}
									North_Main_DMA_PRD_start_addr = North_Main_DMA_PRD_start_addr_init;
								}
								full_data_length = remained_data_length = 2*SSD_BL;
							}
/*
							if ((addr.low_address >= North_Main_DMA_check_reg_start_addr.low_address) && ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[0] >> 6) & 0x1))
							{
								if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out) // buffer overflow must be resolved in the near future 
								{
									tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
									DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
									DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
									DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
									DRAM_buffer_TLP_up_time = sc_time_stamp();
								}
							}
*/
							if (!packet_resolved)
							{
								if ((DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[0] >> 6) & 0x1)
								{
									SSD_is_Write = true;
#ifdef	DEBUG_RC_SSD_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Start Write to SSD port" << endl;
#endif
								}
								else
								{
									SSD_is_Write = false;
									data = new unsigned[full_data_length];
#ifdef	DEBUG_RC_SSD_CTRL
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Start Read to SSD port" << endl;
#endif
								}
								SDRAM_current_col_addr = (addr.low_address-system_address_map[0].end_addr.low_address/2+1) >> 12;
								packet_resolved = true;
							}
							col_addr = SDRAM_current_col_addr;
							if (tRCD_cnt != 1)
							{
								SSD_curr_state = SDRAM_ROW_ACT;
							}
							else
							{
								if(!SSD_is_Write)
									SSD_curr_state = SDRAM_READ_AP;
								else
									SSD_curr_state = SDRAM_WRITE_AP;
							}
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Row Activate at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Row=0x" << row_addr << dec << endl;
#endif
							SSD_port->SDRAM_row_activate(rank_sel, bank_sel, row_addr);
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Row Activate...tRCD count : " << tRCD_cnt << endl;
#endif
							tRCD_cnt--;
							if (tRCD_cnt == 0)
								tRCD_cnt=SSD_tRCD;
						}
						else if ((addr.low_address >= system_address_map[1].end_addr.low_address/2+1) && (addr.low_address >= system_address_map[1].end_addr.low_address))
						{
							if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out)
							{
								tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
								DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
								DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
								DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
								DRAM_buffer_TLP_up_time = sc_time_stamp();
							}
						}
						else if ((addr.low_address >= system_address_map[2].start_addr.low_address/2+1) && (addr.low_address >= system_address_map[2].start_addr.low_address))
						{
/*
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> MRS commanded : 0xA62 (burst_length = 4)" << endl;
#endif
							SSD_port->SDRAM_DDR_mode_register_set(0, 0xA62);
							SSD_curr_state = SDRAM_MRS;
*/
							if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out)
							{
								tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
								DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
								DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
								DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
								DRAM_buffer_TLP_up_time = sc_time_stamp();
							}
						}
					}
				}
			}
			break;
		case SDRAM_ROW_ACT:
			if (DRAM_CLK == true)
			{
#ifdef	DEBUG_RC_SSD_CTRL
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Row Activate...tRCD count : " << tRCD_cnt << endl;
#endif
				tRCD_cnt--;
				if (tRCD_cnt == 0)
				{
					if(!SSD_is_Write)
						SSD_curr_state = SDRAM_READ_AP;
					else
						SSD_curr_state = SDRAM_WRITE_AP;
					tRCD_cnt=SSD_tRCD;
				}
			}
			break;
		case SDRAM_READ:
		case SDRAM_READ_AP:
			if ((CL_cnt == SSD_CL) && (DRAM_CLK == true))
			{
#ifdef	DEBUG_RC_SSD_CTRL
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Read Command at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Col=0x" << col_addr << dec << endl;
#endif
				SSD_port->SDRAM_read_command(rank_sel, bank_sel, col_addr, true);
			}
			if (CL_cnt != 0)
			{
				if (DRAM_CLK == true)
				{
#ifdef	DEBUG_RC_SSD_CTRL
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting CAS Latency...CL count : " << CL_cnt << endl;
#endif
					CL_cnt--;
				}
			}
			else
			{
				if (((BL_cnt != 0) && (SSD_port->SDRAM_DDR_get_DQS() != 'Z')) || (BL_cnt == 0))
				{
					if ((BL_cnt != SSD_BL) || (DRAM_CLK == true))
					{
						if (BL_cnt != 0)
						{
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Before Read data : 0x" << hex << SDRAM_current_data.upper_bytes << " | 0x" << SDRAM_current_data.lower_bytes << dec;
#endif
							SDRAM_current_data = SSD_port->SDRAM_DDR_read_data(rank_sel, bank_sel, DDR_DEFAULT_BURST_LENGTH-BL_cnt, false);
							data[(full_data_length-remained_data_length)+2*(SSD_BL-BL_cnt)] = SDRAM_current_data.lower_bytes;
							data[(full_data_length-remained_data_length)+2*(SSD_BL-BL_cnt)+1] = SDRAM_current_data.upper_bytes;
#ifdef	DEBUG_RC_SSD_CTRL
							cout << ", After Read data : 0x" << hex << SDRAM_current_data.upper_bytes << " | 0x" << SDRAM_current_data.lower_bytes << dec << endl;
#endif
							BL_cnt--;
						}
						if ((BL_cnt == 0) && (DRAM_CLK == true))
						{
							SSD_port->SDRAM_precharge(rank_sel, bank_sel, false);
							if (tRP_cnt != 1)
								SSD_curr_state = SDRAM_PRECHARGE;
							else
								SSD_curr_state = SDRAM_IDLE;
							CL_cnt = SSD_CL;
							BL_cnt = SSD_BL;
							SDRAM_current_col_addr += 8*SSD_BL;
							remained_data_length -= 2*SSD_BL;
							if (remained_data_length == 0)
							{
//#ifdef	DEBUG_RC_SDRAM_CTRL
								if (full_data_length == 1024)
									cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> SSD I/F Read is finished." <<endl;
//#endif
								if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out) // buffer overflow must be resolved in the near future 
								{
									if (full_data_length == 1024)
										tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
									else
										tlp = construct_TLP_Completion(true, COMPLETION, 0, true, false, false, false, 2*SSD_BL, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 0, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, data, 0);
									delete[] data;
									DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
									DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
									DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
									DRAM_buffer_TLP_up_time = sc_time_stamp();
									full_data_length = remained_data_length = 1024;
									packet_resolved = false;
								}
							}
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count : " << tRP_cnt << endl;
#endif
							tRP_cnt--;
							if(tRP_cnt==0)
								tRP_cnt = SSD_tRP;
						}
					}
				}
			}
			break;
		case SDRAM_WRITE:
		case SDRAM_WRITE_AP:
			if (tDQSS_cnt == SSD_tDQSS)
			{
				if (DRAM_CLK == true)
				{
#ifdef	DEBUG_RC_SSD_CTRL
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Write Command at Rank=" << hex << rank_sel << ", Bank=" << bank_sel << ", Col=0x" << col_addr << dec << endl;
#endif
					SSD_port->SDRAM_write_command(rank_sel, bank_sel, col_addr, true);
					if (SSD_port->SDRAM_DDR_get_DQS() == 'Z')
					{
						SSD_port->SDRAM_DDR_set_DQS(sc_logic('0'));
					}
					else
					{
						cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> DQS signal is not valid." << endl;
						sc_stop();
					}
#ifdef	DEBUG_RC_SSD_CTRL
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting DQS Transition...tDQSS count : " << tDQSS_cnt << endl;
#endif
					tDQSS_cnt--;
				}
			}
			else
			{
				if (tDQSS_cnt != 0)
				{
#ifdef	DEBUG_RC_SSD_CTRL
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting DQS Transition...tDQSS count : " << tDQSS_cnt << endl;
#endif
					tDQSS_cnt--;
				}
				else
				{
					if (BL_cnt != 0)
					{
						if (addr.low_address >= North_DMA_cmd_reg_start_addr.low_address)
						{
							if (BL_cnt == SSD_BL)
							{
								SDRAM_current_data.lower_bytes = North_SSD_DMA_command;
								SDRAM_current_data.upper_bytes = North_SSD_DMA_sector_cnt;
							}
							else
							{
								SDRAM_current_data.lower_bytes = North_SSD_DMA_LBA;
								SDRAM_current_data.upper_bytes = North_SSD_DMA_PRD_length;
							}
						}
						else
						{
							SDRAM_current_data.lower_bytes = DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].data[(full_data_length-remained_data_length)+2*(SSD_BL-BL_cnt)];
							SDRAM_current_data.upper_bytes = DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].data[(full_data_length-remained_data_length)+2*(SSD_BL-BL_cnt)+1];
						}
#ifdef	DEBUG_RC_SSD_CTRL
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Write data : 0x" << hex << SDRAM_current_data.upper_bytes << " | 0x" << SDRAM_current_data.lower_bytes << dec << endl;
#endif
						SSD_port->SDRAM_DDR_write_data(rank_sel, bank_sel, DDR_DEFAULT_BURST_LENGTH-BL_cnt, SDRAM_current_data, false);
						if (SSD_port->SDRAM_DDR_get_DQS() == '0')
						{
							SSD_port->SDRAM_DDR_set_DQS(sc_logic('1'));
						}
						else if (SSD_port->SDRAM_DDR_get_DQS() == '1')
						{
							SSD_port->SDRAM_DDR_set_DQS(sc_logic('0'));
						}
						else
						{
							cout << "ERROR @ " << sc_module::name() << "[" << sc_time_stamp() << "]> DQS signal is not valid." << endl;
							sc_stop();
						}
						BL_cnt--;
					}
					if ((BL_cnt == 0) && (DRAM_CLK == true))
					{
						if (tWR_cnt != 0)
						{
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tWR count : " << tWR_cnt << endl;
#endif
							tWR_cnt--;
						}
						else
						{
							SSD_port->SDRAM_DDR_set_DQS(sc_logic('Z'));
							if (tRP_cnt != 1)
								SSD_curr_state= SDRAM_PRECHARGE;
							else
								SSD_curr_state = SDRAM_IDLE;
							tDQSS_cnt = SSD_tDQSS;
							BL_cnt = SSD_BL;
							SDRAM_current_col_addr += 8*SSD_BL;
							remained_data_length -= 2*SSD_BL;
							if (remained_data_length == 0)
							{
								if ((DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC != DRAM_buffer_TLP_up_out) // buffer overflow must be resolved in the near future 
								{
									tlp = construct_TLP_Completion(false, COMPLETION, 0, true, false, false, false, 0, id>>8, (id & 0xFF)>>3, id & 0x7, 0, false, 1*4, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[4], (DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5])>>3, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[5] & 0x7, DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_out].header[6], 0, NULL, 0);
									DRAM_buffer_TLP_up[DRAM_buffer_TLP_up_in] = tlp;
									DRAM_buffer_TLP_down_out = (DRAM_buffer_TLP_down_out+1)%MAX_BUFFER_RC;
									DRAM_buffer_TLP_up_in = (DRAM_buffer_TLP_up_in+1)%MAX_BUFFER_RC;
									DRAM_buffer_TLP_up_time = sc_time_stamp();
									full_data_length = remained_data_length = 1024;
									packet_resolved = false;
								}
							}
#ifdef	DEBUG_RC_SSD_CTRL
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count : " << tRP_cnt << endl;
#endif
							tRP_cnt--;
							if(tRP_cnt==0)
								tRP_cnt = SSD_tRP;
						}
					}
				}
			}
			break;
		case SDRAM_PRECHARGE:
			 if (DRAM_CLK == true)
			 {
#ifdef	DEBUG_RC_SSD_CTRL
				cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Waiting Precharge...tRP count : " << tRP_cnt << endl;
#endif
				tRP_cnt--;
				if(tRP_cnt == 0)
				{
					SSD_curr_state=SDRAM_IDLE;
					tRP_cnt = SSD_tRP;
//#ifdef	DEBUG_RC_SDRAM_CTRL
					if (!SSD_is_Write)
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> SSD I/F Read is finished." <<endl;
//#endif
				}
			 }
			break;
		case SDRAM_MRS:
			if (DRAM_CLK == true)
				SSD_curr_state=SDRAM_IDLE;
			break;
		case SDRAM_AUTO_REF:
		case SDRAM_SELF_REF:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unsupported State in SSD Controller!" << endl << flush;
			sc_stop();
			break;
		default:
			cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Unknown State!" << endl << flush;
			sc_stop();
		}
		wait();
	}
}

void
PCIe_Root_Complex::North_Main_DMA_action()
{
	PCIe_TLP tlp;

	while (true)
	{
		if (North_Main_DMA_enable && North_Main_DMA_enable_time != sc_time_stamp())
		{
			if (North_Main_DMA_command == 0xCA)
			{
				if (!North_Main_DMA_PRD_fetch_commanded)
				{
					tlp= construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 2*North_Main_DMA_PRD_length, North_DMA_id >>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, 0xFF, North_Main_DMA_PRD_start_addr.low_address, NULL, 0);
					DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
					DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
					DRAM_buffer_TLP_down_time = sc_time_stamp();
					North_Main_DMA_PRD_fetch_commanded = true;
//#ifdef	DEBUG_RC
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "PRD for North Main-DMA is requested." << endl;
//#endif
				}
				else if (North_Main_DMA_PRD_fetched && North_Main_DMA_PRD_fetched_time != sc_time_stamp())
				{
					if ((!North_Main_DMA_requested_1st) && (DRAM_buffer_TLP_down_in+1 != DRAM_buffer_TLP_down_out))
					{
						tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 0, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, 0xFF, North_Main_DMA_base_addr, NULL, 0);
						North_Main_DMA_requested_1st = true;
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
						DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DRAM_buffer_TLP_down_time = sc_time_stamp();
//#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Request data to main memory"<< endl;
//#endif
					}
					else if ((North_Main_DMA_buffered && !North_Main_DMA_requested_2nd) && (North_Main_DMA_buffered_time != sc_time_stamp()) && (DRAM_buffer_TLP_down_in+1 != DRAM_buffer_TLP_down_out))
					{
						tlp = construct_TLP_Request_Memory_32(true, MEMORY, 0, true, false, false, false, 0, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, 0xFF, (system_address_map[0].end_addr.low_address/2+1)+(North_Main_DMA_LBA_current<<12), North_Main_DMA_buffer, 0);
						North_Main_DMA_requested_2nd = true;
						North_Main_DMA_LBA_current += North_Main_DMA_base_cnt;
						PRD_current--;
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
						DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DRAM_buffer_TLP_down_time = sc_time_stamp();
//#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "Write to SSD started." << endl;
//#endif
					}
				}
			}
			else
			{
				if ((!North_Main_DMA_requested_1st) && (DRAM_buffer_TLP_down_in+1 != DRAM_buffer_TLP_down_out))
				{
					tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 0, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, 0xFF, (system_address_map[0].end_addr.low_address/2+1)+(North_Main_DMA_LBA_current<<12), NULL, 0);
					North_Main_DMA_requested_1st = true;
					DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
					DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
					DRAM_buffer_TLP_down_time = sc_time_stamp();
//#ifdef	DEBUG_RC
					cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> SSD Internal Read commanded."<<endl;
//#endif
				}
				else if ((North_Main_DMA_buffered) && (North_Main_DMA_buffered_time != sc_time_stamp()))
				{
					if ((!North_Main_DMA_PRD_fetch_commanded) && (DRAM_buffer_TLP_down_in+1 != DRAM_buffer_TLP_down_out))
					{
						tlp = construct_TLP_Request_Memory_32(false, MEMORY, 0, true, false, false, false, 2*North_Main_DMA_PRD_length, North_DMA_id >>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, 0xFF, North_Main_DMA_PRD_start_addr.low_address, NULL, 0);
						DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
						DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
						DRAM_buffer_TLP_down_time = sc_time_stamp();
						North_Main_DMA_PRD_fetch_commanded = true;
//#ifdef	DEBUG_RC
						cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> " << "PRD for North Main-DMA is requested." << endl;
//#endif
					}
					else if ((North_Main_DMA_PRD_fetched) && (North_Main_DMA_PRD_fetched_time != sc_time_stamp()))
					{
						if ((!North_Main_DMA_requested_2nd) && (DRAM_buffer_TLP_down_in+1 != DRAM_buffer_TLP_down_out))
						{
							tlp = construct_TLP_Request_Memory_32(true, MEMORY, 0, true, false, false, false, 0, North_DMA_id>>8, (North_DMA_id & 0xFF)>>3, North_DMA_id & 0x7, 0, 0xFF, North_Main_DMA_base_addr, North_Main_DMA_buffer, 0);
							North_Main_DMA_requested_2nd = true;
							DRAM_buffer_TLP_down[DRAM_buffer_TLP_down_in] = tlp;
							DRAM_buffer_TLP_down_in = (DRAM_buffer_TLP_down_in+1)%MAX_BUFFER_RC;
							DRAM_buffer_TLP_down_time = sc_time_stamp();
							North_Main_DMA_LBA_current += North_Main_DMA_base_cnt;
							PRD_current--;
							if (PRD_current != 0)
								North_Main_DMA_requested_1st = false;
//#ifdef	DEBUG_RC
							cout << "[" << sc_time_stamp() << "] " << sc_module::name() << "> Send data to main memory"<< endl;
//#endif
						}
					}
				}
			}
		}
		wait();
	}
}